index.vue 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726
  1. <template>
  2. <basic-container>
  3. <avue-crud :option="option"
  4. :table-loading="loading"
  5. :data="data"
  6. :page.sync="page"
  7. :permission="permissionList"
  8. :before-open="beforeOpen"
  9. :upload-error="uploadError"
  10. :upload-after="uploadAfter"
  11. v-model="form"
  12. ref="crud"
  13. @row-update="rowUpdate"
  14. @row-click="handleRowClick"
  15. @row-save="rowSave"
  16. @row-del="rowDel"
  17. @search-change="searchChange"
  18. @search-reset="searchReset"
  19. @selection-change="selectionChange"
  20. @current-change="currentChange"
  21. @size-change="sizeChange"
  22. @refresh-change="refreshChange"
  23. @on-load="onLoad">
  24. <template slot="isSale" slot-scope="scope" >
  25. <el-tag v-if="scope.row.$isSale === '上架'" type="success">{{scope.row.$isSale}}</el-tag>
  26. <el-tag v-if="scope.row.$isSale === '下架'" type="danger">{{scope.row.$isSale}}</el-tag>
  27. </template>
  28. <template slot="auditStatus" slot-scope="scope" >
  29. <el-tag v-if="scope.row.auditStatus === 0">{{scope.row.$auditStatus}}</el-tag>
  30. <el-tag v-else-if="scope.row.auditStatus === 1" type="success">{{scope.row.$auditStatus}}</el-tag>
  31. <el-tag v-else-if="scope.row.auditStatus === 2"type="danger">{{scope.row.$auditStatus}}</el-tag>
  32. </template>
  33. <template slot-scope="scope" slot="menu">
  34. <el-button v-if="scope.row.isSale == 1"
  35. type="text"
  36. size="small"
  37. @click="modifyGoodsState(scope.row.id, 0)"
  38. >下架</el-button>
  39. <el-button v-if="scope.row.isSale == 0"
  40. type="text"
  41. size="small"
  42. @click="modifyGoodsState(scope.row.id, 1)"
  43. >上架
  44. </el-button>
  45. <el-button v-if="scope.row.auditStatus == 0"
  46. type="text"
  47. size="small"
  48. @click="openAuditBox(scope.row.id)"
  49. >审核</el-button>
  50. </template>
  51. </avue-crud>
  52. <el-dialog title="商品审核" @close="refreshChange"
  53. append-to-body
  54. :visible.sync="auditBox"
  55. :before-close="handleClose"
  56. width="600px"
  57. heigh="40%">
  58. <el-form :model="auditForm" label-width="80px">
  59. <el-form-item label="审核意见:">
  60. <el-select v-model="auditForm.auditStatus" placeholder="请选择">
  61. <el-option
  62. v-for="item in auditList"
  63. :key="item.value"
  64. :label="item.name"
  65. :value="item.value">
  66. </el-option>
  67. </el-select>
  68. </el-form-item>
  69. <el-form-item label="驳回描述:" v-if="auditForm.auditStatus == 2">
  70. <el-input type="textarea" v-model="auditForm.remark" :autosize="{ minRows: 3, maxRows: 5}"></el-input>
  71. </el-form-item>
  72. </el-form>
  73. <div slot="footer" class="dialog-footer">
  74. <el-button @click="handleClose">取 消</el-button>
  75. <el-button type="primary" @click="auditGoods()">确 定</el-button>
  76. </div>
  77. </el-dialog>
  78. </basic-container>
  79. </template>
  80. <script>
  81. import {getList, getDetail, add, update, remove, modifyState, audit} from "@/api/mall/storegoodsinfo";
  82. import {mapGetters} from "vuex";
  83. import {getByParentId} from "../../../api/mall/categoryinfo";
  84. export default {
  85. data() {
  86. var validatePass = (rule, value, callback) => {
  87. if (value>=10 || value <=0) {
  88. callback(new Error('非法的折扣'));
  89. } else {
  90. callback();
  91. }
  92. }
  93. return {
  94. option: {
  95. height: 'auto',
  96. calcHeight: 30,
  97. border: true,
  98. index: false,
  99. viewBtn: true,
  100. delBtn:false,
  101. editBtn: true,
  102. // selection: true,
  103. dialogClickModal: false,
  104. labelWidth: 150,
  105. searchIcon: true,
  106. searchIndex: 3,
  107. column: [
  108. {
  109. label: "商品编号",
  110. search: true,
  111. prop: "id",
  112. overHidden: true,
  113. addDisplay: false,
  114. editDisplay: false,
  115. editDisabled: true,
  116. width: 160
  117. },
  118. {
  119. label: "商品封面",
  120. width: 80,
  121. prop: "goodsCover",
  122. addDisplay: false,
  123. viewDisplay: false,
  124. editDisplay: false,
  125. type: 'img',
  126. },
  127. {
  128. label: "商品名称",
  129. prop: "goodsName",
  130. search: true,
  131. width: 280,
  132. overHidden: true,
  133. rules: [{
  134. required: true,
  135. message: "请输入商品名称",
  136. trigger: "blur"
  137. }]
  138. },
  139. {
  140. label: "规格",
  141. prop: "goodsSpec",
  142. editDisplay: false,
  143. rules: [{
  144. required: true,
  145. message: "请输入规格",
  146. trigger: "blur"
  147. }]
  148. },
  149. {
  150. label: "品牌",
  151. prop: "brandDesc",
  152. hide: true,
  153. addDisplay: false,
  154. viewDisplay: false,
  155. editDisplay: false,
  156. },
  157. {
  158. label: "分类",
  159. prop: "categoryIdArr",
  160. hide: true,
  161. search: true,
  162. lazy: true,
  163. rules: [{
  164. required: true,
  165. message: "请选择分类",
  166. trigger: "blur"
  167. }],
  168. type: "cascader",
  169. filterable: true,
  170. checkStrictly: true,
  171. lazyLoad(node, resolve) {
  172. let parentId;
  173. let stop_level = 2;
  174. let level = node.level;
  175. let list = [];
  176. if (node.level === 0) {
  177. parentId = 0;
  178. getByParentId(0).then((res) => {
  179. list = res.data.data;
  180. list = (list || []).map(ele => {
  181. return Object.assign(ele, {
  182. leaf: level >= stop_level
  183. })
  184. })
  185. resolve(list)
  186. })
  187. } else {
  188. parentId = node.data.id;
  189. getByParentId(node.data.id).then((res) => {
  190. list = res.data.data;
  191. list = (list || []).map(ele => {
  192. return Object.assign(ele, {
  193. leaf: level >= stop_level
  194. })
  195. })
  196. resolve(list)
  197. })
  198. }
  199. },
  200. props: {
  201. label: "title",
  202. value: "key"
  203. },
  204. },
  205. {
  206. label: "品牌",
  207. prop: "brandId",
  208. hide: true,
  209. search: true,
  210. rules: [{
  211. required: true,
  212. message: "请选择品牌",
  213. trigger: "blur"
  214. }],
  215. type: "select",
  216. remote: true,
  217. dicUrl: "/api/mall/brandsinfo/getByName?brandName={{key}}",
  218. props: {
  219. label: "brandName",
  220. value: "id"
  221. },
  222. dataType: "string",
  223. },
  224. {
  225. label: "折扣",
  226. prop: "discount",
  227. hide: true,
  228. precision: 2,
  229. type: "number",
  230. rules: [{
  231. required: true,
  232. message: "请输入折扣",
  233. trigger: "blur"
  234. },{ validator: validatePass, trigger: 'blur' }],
  235. },
  236. {
  237. label: "价格",
  238. prop: "salePrice",
  239. precision: 2,
  240. type: "number",
  241. formatter:(val,value)=>{
  242. return Number(value).toFixed(2);
  243. },
  244. rules: [{
  245. required: true,
  246. message: "请输入销售价",
  247. trigger: "blur"
  248. }],
  249. },
  250. {
  251. label: "状态",
  252. prop: "isSale",
  253. search: true,
  254. slot:true,
  255. rules: [{
  256. required: true,
  257. message: "请输入是否上架",
  258. trigger: "blur"
  259. }],
  260. type: "select",
  261. dicUrl: "/api/blade-system/dict-biz/getEnumDict?enumName=GoodsStateEnum",
  262. props: {
  263. label: "name",
  264. value: "value"
  265. },
  266. dataType: "number",
  267. },
  268. {
  269. label: "上架时间",
  270. prop: "saleTime",
  271. hide: true,
  272. addDisplay: false,
  273. viewDisplay: false,
  274. editDisplay: false,
  275. editDisabled: true,
  276. },
  277. {
  278. label: "总库存",
  279. prop: "totalStock",
  280. type: "number",
  281. hide: true,
  282. min: 1,
  283. rules: [
  284. {required: true, message: "请输入总库存", trigger: "blur"},
  285. ]
  286. },
  287. {
  288. label: "总销量",
  289. prop: "totalSales",
  290. hide: true,
  291. addDisplay: false,
  292. editDisplay: false,
  293. },
  294. {
  295. label: "总浏览量",
  296. prop: "totalViews",
  297. hide: true,
  298. addDisplay: false,
  299. editDisplay: false,
  300. },
  301. {
  302. label: "单位",
  303. prop: "unit",
  304. hide: true,
  305. rules: [{
  306. required: true,
  307. message: "请选择单位",
  308. trigger: "blur"
  309. }],
  310. type: "select",
  311. remote: true,
  312. dicUrl: "/api/mall/unit/all-list",
  313. props: {
  314. label: "name",
  315. value: "id"
  316. },
  317. dataType: "string",
  318. },
  319. {
  320. label: "产地",
  321. prop: "origin",
  322. hide: true,
  323. },
  324. {
  325. label: "创建时间",
  326. prop: "createTime",
  327. hide: true,
  328. addDisplay: false,
  329. editDisplay: false,
  330. editDisabled: false,
  331. },
  332. {
  333. label: '商品封面',
  334. prop: 'uploadCover',
  335. type: 'upload',
  336. listType: 'picture-img',
  337. loadText: '上传中,请稍等',
  338. accept: 'image/png, image/jpeg',
  339. fileSize: 1024,
  340. tip: '只能上传jpg/png文件,且不超过1M',
  341. span: 24,
  342. hide: true,
  343. propsHttp: {
  344. res: 'data',
  345. url: 'link',
  346. },
  347. action: "/api/blade-resource/oss/endpoint/put-file-attach"
  348. },
  349. {
  350. label: '商品轮播图',
  351. prop: 'slideshowList',
  352. type: 'upload',
  353. dataType: 'array',
  354. listType: 'picture-card',
  355. loadText: '上传中,请稍等',
  356. accept: 'image/png, image/jpeg',
  357. fileSize: 1024,
  358. tip: '只能上传jpg/png文件,且不超过1M',
  359. span: 24,
  360. hide: true,
  361. propsHttp: {
  362. res: 'data',
  363. url: 'link',
  364. },
  365. action: "/api/blade-resource/oss/endpoint/put-file-attach"
  366. },
  367. {
  368. label: '图文详情',
  369. prop: 'detailImgUrlList',
  370. type: 'upload',
  371. dataType: 'array',
  372. listType: 'picture-card',
  373. loadText: '上传中,请稍等',
  374. accept: 'image/png, image/jpeg',
  375. fileSize: 2048,
  376. tip: '只能上传jpg/png文件,且不超过2M',
  377. limit: 25,
  378. span: 24,
  379. hide: true,
  380. propsHttp: {
  381. res: 'data',
  382. url: 'link',
  383. },
  384. action: "/api/blade-resource/oss/endpoint/put-file-attach"
  385. },
  386. ]
  387. },
  388. range: {
  389. from: '',
  390. to: ''
  391. },
  392. categoryData: [],
  393. props: {
  394. label: "title",
  395. value: "key"
  396. },
  397. categoryIdArr: [],
  398. auditBox: false,
  399. auditForm: {
  400. auditStatus: '',
  401. id: '',
  402. remark: ''
  403. },
  404. form: {
  405. },
  406. goodsParamForm: {},
  407. goodsSpecForm: {},
  408. scForm: {},
  409. query: {},
  410. goodsParamQuery: {},
  411. viewSpecQuery: {},
  412. loading: true,
  413. paramLoading: true,
  414. box: false,
  415. page: {
  416. pageSize: 10,
  417. currentPage: 1,
  418. total: 0
  419. },
  420. data: [],
  421. goodsParamData: [],
  422. viewSpecData: [],
  423. scData: [],
  424. viewDialog: false,
  425. auditList: [
  426. {name: '通过', value: 1},{name: '驳回', value: 2}
  427. ]
  428. };
  429. },
  430. computed: {
  431. ...mapGetters(["permission"]),
  432. permissionList() {
  433. return {
  434. // addBtn: this.vaildData(this.permission.goodsinfo_add, false),
  435. // viewBtn: this.vaildData(this.permission.goodsinfo_view, false),
  436. // delBtn: this.vaildData(this.permission.goodsinfo_delete, false),
  437. // editBtn: this.vaildData(this.permission.goodsinfo_edit, false)
  438. };
  439. },
  440. ids() {
  441. let ids = [];
  442. this.selectionList.forEach(ele => {
  443. ids.push(ele.id);
  444. });
  445. return ids.join(",");
  446. },
  447. specIds() {
  448. let ids = [];
  449. this.specSelectionList.forEach(ele => {
  450. ids.push(ele.id);
  451. });
  452. return ids.join(",");
  453. }
  454. },
  455. methods: {
  456. viewDialogShow(row) {
  457. this.viewDialog = true;
  458. this.demoModelSrc = `${this.demoModelSrcYuan}?aa=${JSON.stringify(row)}`
  459. },
  460. rowSave(row, done, loading) {
  461. row.goodsCategoryId = row.categoryIdArr.join("-");
  462. if (row.promotionRateRange == '') {
  463. delete row.promotionRateRange;
  464. }
  465. add(row).then(() => {
  466. this.onLoad(this.page);
  467. this.$message({
  468. type: "success",
  469. message: "操作成功!"
  470. });
  471. done();
  472. }, error => {
  473. loading();
  474. window.console.log(error);
  475. });
  476. },
  477. rowUpdate(row, index, done, loading) {
  478. row.goodsCategoryId = row.categoryIdArr.join("-") + "-";
  479. if (row.promotionRateRange == '') {
  480. delete row.promotionRateRange;
  481. }
  482. update(row).then(() => {
  483. this.onLoad(this.page);
  484. this.$message({
  485. type: "success",
  486. message: "操作成功!"
  487. });
  488. done();
  489. }, error => {
  490. loading();
  491. console.log(error);
  492. });
  493. },
  494. rowDel(row) {
  495. this.$confirm("确定将选择数据删除?", {
  496. confirmButtonText: "确定",
  497. cancelButtonText: "取消",
  498. type: "warning"
  499. })
  500. .then(() => {
  501. return remove(row.id);
  502. })
  503. .then(() => {
  504. this.onLoad(this.page);
  505. this.$message({
  506. type: "success",
  507. message: "操作成功!"
  508. });
  509. });
  510. },
  511. handleDelete() {
  512. if (this.selectionList.length === 0) {
  513. this.$message.warning("请选择至少一条数据");
  514. return;
  515. }
  516. this.$confirm("确定将选择数据删除?", {
  517. confirmButtonText: "确定",
  518. cancelButtonText: "取消",
  519. type: "warning"
  520. })
  521. .then(() => {
  522. return remove(this.ids);
  523. })
  524. .then(() => {
  525. this.onLoad(this.page);
  526. this.$message({
  527. type: "success",
  528. message: "操作成功!"
  529. });
  530. this.$refs.crud.toggleSelection();
  531. });
  532. },
  533. beforeOpen(done, type) {
  534. if (["edit", "view"].includes(type)) {
  535. getDetail(this.form.id).then(res => {
  536. this.form = res.data.data;
  537. this.form.uploadCover = res.data.data.goodsCover;
  538. this.form.goodsVideo = res.data.data.videoUrl;
  539. this.form.slideshowList = res.data.data.slideshowList;
  540. this.form.detailImgUrlList = res.data.data.detailImgUrlList;
  541. this.form.categoryIdArr = this.form.goodsCategoryId.split("-");
  542. });
  543. console.log(this.form.goodsCategoryId.split("-"));
  544. }
  545. done();
  546. },
  547. searchReset() {
  548. this.query = {};
  549. this.range = {
  550. from: '',
  551. to: ''
  552. };
  553. this.activityDate = '';
  554. this.onLoad(this.page);
  555. },
  556. searchChange(params, done) {
  557. this.query = params;
  558. this.page.currentPage = 1;
  559. this.onLoad(this.page, params);
  560. done();
  561. },
  562. selectionChange(list) {
  563. this.selectionList = list;
  564. },
  565. selectionClear() {
  566. this.selectionList = [];
  567. this.$refs.crud.toggleSelection();
  568. },
  569. currentChange(currentPage){
  570. this.page.currentPage = currentPage;
  571. },
  572. sizeChange(pageSize){
  573. this.page.pageSize = pageSize;
  574. },
  575. refreshChange() {
  576. this.onLoad(this.page, this.query);
  577. },
  578. onLoad(page, params = {}) {
  579. this.loading = true;
  580. if (this.query.categoryIdArr) {
  581. this.query.goodsCategoryId = this.query.categoryIdArr.join("-");
  582. this.query.categoryIdArr = null;
  583. }
  584. this.query.activityDate = this.activityDate;
  585. getList(page.currentPage, page.pageSize, Object.assign(params, this.query)).then(res => {
  586. const data = res.data.data;
  587. this.page.total = data.total;
  588. this.data = data.records;
  589. this.loading = false;
  590. this.selectionClear();
  591. });
  592. },
  593. uploadError(error, column) {
  594. this.$message.success('上传失败:' + error)
  595. console.log(error, column)
  596. },
  597. uploadAfter(res, done, loading,column) {
  598. console.log(res,column)
  599. if(column.prop == "uploadCover") {
  600. this.form.goodsCover = res.link;
  601. }
  602. if (column.prop == "goodsVideo") {
  603. this.form.videoUrl = res.link;
  604. }
  605. done()
  606. },
  607. paramConfig(row) {
  608. this.box = true;
  609. this.goodsParamQuery.goodsId = row.id;
  610. this.onLoadParam();
  611. },
  612. handleRowClick(row, event, column, loading) {
  613. if (event.label == '是否上架') {
  614. const param = {id:row.id, isSale:row.saleSwitch ? 1 : 0}
  615. update(param).then(() => {
  616. this.onLoad(this.page);
  617. this.$message({
  618. type: "success",
  619. message: row.saleSwitch ? "上架成功" : "下架成功"
  620. });
  621. }, error => {
  622. loading();
  623. console.log(error);
  624. });
  625. }
  626. },
  627. handleClose() {
  628. this.categoryIdArr = [];
  629. this.auditBox = false;
  630. this.auditForm = {
  631. auditStatus: '',
  632. id: '',
  633. remark: ''
  634. };
  635. },
  636. modifyGoodsStateBatch(state) {
  637. if (this.selectionList.length === 0) {
  638. this.$message.warning("请选择至少一条数据");
  639. return;
  640. }
  641. this.$confirm("确定修改数据?", {
  642. confirmButtonText: "确定",
  643. cancelButtonText: "取消",
  644. type: "warning"
  645. })
  646. .then(() => {
  647. const loading = this.$loading({
  648. lock: true,
  649. text: '修改中,请稍等...',
  650. spinner: 'el-icon-loading',
  651. background: 'rgba(0, 0, 0, 0.7)'
  652. });
  653. modifyState(this.ids, state).then(() => {
  654. loading.close();
  655. this.onLoad(this.page, this.query);
  656. this.$message({
  657. type: "success",
  658. message: "操作成功!"
  659. });
  660. this.selectionClear()
  661. });
  662. })
  663. },
  664. modifyGoodsState(id, state) {
  665. let title = state === 0 ? '确定下架?' : '确定上架?';
  666. this.$confirm(title, {
  667. confirmButtonText: "确定",
  668. cancelButtonText: "取消",
  669. type: "warning"
  670. }).then(() => {
  671. const loading = this.$loading({
  672. lock: true,
  673. text: '修改中,请稍等...',
  674. spinner: 'el-icon-loading',
  675. background: 'rgba(0, 0, 0, 0.7)'
  676. });
  677. modifyState(id, state).then(() => {
  678. loading.close();
  679. this.onLoad(this.page, this.query);
  680. this.$message({
  681. type: "success",
  682. message: "操作成功!"
  683. });
  684. this.selectionClear()
  685. });
  686. })
  687. },
  688. openAuditBox(id) {
  689. this.auditBox = true;
  690. this.auditForm.id = id;
  691. },
  692. auditGoods() {
  693. audit(this.auditForm).then(() => {
  694. this.auditBox = false;
  695. this.onLoad(this.page, this.query);
  696. this.$message({
  697. type: "success",
  698. message: "操作成功!"
  699. });
  700. }, error => {
  701. loading();
  702. console.log(error);
  703. });
  704. }
  705. }
  706. };
  707. </script>
  708. <style>
  709. </style>