index.vue 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703
  1. <template> 
  2. <div class="app-container">
  3. <el-card class="filter-container" shadow="never">
  4. <div>
  5. <i class="el-icon-search"></i>
  6. <span>筛选搜索</span>
  7. <el-button
  8. style="float: right"
  9. @click="handleSearchList()"
  10. type="primary"
  11. size="small">
  12. 查询结果
  13. </el-button>
  14. <el-button
  15. style="float: right;margin-right: 15px"
  16. @click="handleResetSearch()"
  17. size="small">
  18. 重置
  19. </el-button>
  20. </div>
  21. <div style="margin-top: 15px">
  22. <el-form :inline="true" :model="listQuery" size="small" label-width="140px">
  23. <el-form-item label="输入搜索:">
  24. <el-input style="width: 203px" v-model="listQuery.keyword" placeholder="商品名称"></el-input>
  25. </el-form-item>
  26. <el-form-item label="商品货号:">
  27. <el-input style="width: 203px" v-model="listQuery.productSn" placeholder="商品货号"></el-input>
  28. </el-form-item>
  29. <el-form-item label="商品分类:">
  30. <el-cascader
  31. clearable
  32. v-model="selectProductCateValue"
  33. :options="productCateOptions">
  34. </el-cascader>
  35. </el-form-item>
  36. <el-form-item label="商品品牌:">
  37. <el-select v-model="listQuery.brandId" placeholder="请选择品牌" clearable>
  38. <el-option
  39. v-for="item in brandOptions"
  40. :key="item.value"
  41. :label="item.label"
  42. :value="item.value">
  43. </el-option>
  44. </el-select>
  45. </el-form-item>
  46. <el-form-item label="上架状态:">
  47. <el-select v-model="listQuery.publishStatus" placeholder="全部" clearable>
  48. <el-option
  49. v-for="item in publishStatusOptions"
  50. :key="item.value"
  51. :label="item.label"
  52. :value="item.value">
  53. </el-option>
  54. </el-select>
  55. </el-form-item>
  56. <el-form-item label="审核状态:">
  57. <el-select v-model="listQuery.verifyStatus" placeholder="全部" clearable>
  58. <el-option
  59. v-for="item in verifyStatusOptions"
  60. :key="item.value"
  61. :label="item.label"
  62. :value="item.value">
  63. </el-option>
  64. </el-select>
  65. </el-form-item>
  66. </el-form>
  67. </div>
  68. </el-card>
  69. <el-card class="operate-container" shadow="never">
  70. <i class="el-icon-tickets"></i>
  71. <span>数据列表</span>
  72. <el-button
  73. v-if="createPermission"
  74. class="btn-add"
  75. @click="handleAddProduct()"
  76. size="mini">
  77. 添加
  78. </el-button>
  79. </el-card>
  80. <div class="table-container">
  81. <el-table ref="productTable"
  82. :data="list"
  83. style="width: 100%"
  84. @selection-change="handleSelectionChange"
  85. v-loading="listLoading"
  86. border>
  87. <el-table-column type="selection" width="60" align="center"></el-table-column>
  88. <el-table-column label="编号" width="100" align="center">
  89. <template slot-scope="scope">{{scope.row.id}}</template>
  90. </el-table-column>
  91. <el-table-column label="商品图片" width="120" align="center">
  92. <template slot-scope="scope"><img style="height: 80px" :src="scope.row.pic"></template>
  93. </el-table-column>
  94. <el-table-column label="商品名称" align="center">
  95. <template slot-scope="scope">
  96. <p>{{scope.row.name}}</p>
  97. <p>品牌:{{scope.row.brandName}}</p>
  98. </template>
  99. </el-table-column>
  100. <el-table-column label="价格/货号" width="120" align="center">
  101. <template slot-scope="scope">
  102. <p>价格:¥{{scope.row.price}}</p>
  103. <p>货号:{{scope.row.productSn}}</p>
  104. </template>
  105. </el-table-column>
  106. <el-table-column label="标签" width="140" align="center">
  107. <template slot-scope="scope">
  108. <p>上架:
  109. <el-switch
  110. @change="handlePublishStatusChange(scope.$index, scope.row)"
  111. :active-value="1"
  112. :inactive-value="0"
  113. v-model="scope.row.publishStatus">
  114. </el-switch>
  115. </p>
  116. <!-- <p>新品:
  117. <el-switch
  118. @change="handleNewStatusChange(scope.$index, scope.row)"
  119. :active-value="1"
  120. :inactive-value="0"
  121. v-model="scope.row.newStatus">
  122. </el-switch>
  123. </p>
  124. <p>推荐:
  125. <el-switch
  126. @change="handleRecommendStatusChange(scope.$index, scope.row)"
  127. :active-value="1"
  128. :inactive-value="0"
  129. v-model="scope.row.recommandStatus">
  130. </el-switch>
  131. </p> -->
  132. </template>
  133. </el-table-column>
  134. <el-table-column label="排序" width="100" align="center">
  135. <template slot-scope="scope">{{scope.row.sort}}</template>
  136. </el-table-column>
  137. <!-- <el-table-column label="SKU库存" width="100" align="center">
  138. <template slot-scope="scope">
  139. <el-button type="primary" icon="el-icon-edit" @click="handleShowSkuEditDialog(scope.$index, scope.row)" circle></el-button>
  140. </template>
  141. </el-table-column> -->
  142. <el-table-column label="销量" width="100" align="center">
  143. <template slot-scope="scope">{{scope.row.sale}}</template>
  144. </el-table-column>
  145. <el-table-column label="保质期" width="100" align="center">
  146. <template slot-scope="scope">{{scope.row.qualityGuaranteePeriod}}</template>
  147. </el-table-column>
  148. <el-table-column label="审核状态" width="100" align="center">
  149. <template slot-scope="scope">
  150. <p>{{scope.row.verifyStatus | verifyStatusFilter}}</p>
  151. <p>
  152. <!-- <el-button
  153. type="text"
  154. @click="handleShowVerifyDetail(scope.$index, scope.row)">审核详情
  155. </el-button> -->
  156. </p>
  157. </template>
  158. </el-table-column>
  159. <el-table-column label="操作" width="160" align="center">
  160. <template slot-scope="scope">
  161. <p>
  162. <!-- <el-button
  163. size="mini"
  164. @click="handleShowProduct(scope.$index, scope.row)">查看
  165. </el-button> -->
  166. <el-button
  167. v-if="updatePermission"
  168. size="mini"
  169. @click="handleUpdateProduct(scope.$index, scope.row)">编辑
  170. </el-button>
  171. </p>
  172. <p>
  173. <!-- <el-button
  174. size="mini"
  175. @click="handleShowLog(scope.$index, scope.row)">日志
  176. </el-button> -->
  177. <el-button size="mini" v-if="scope.row.verifyStatus==0&&verifyPermission" @click="handleVerify(scope.$index, scope.row)">
  178. 审核
  179. </el-button>
  180. <el-button
  181. v-if="delPermission"
  182. size="mini"
  183. type="danger"
  184. @click="handleDelete(scope.$index, scope.row)">删除
  185. </el-button>
  186. </p>
  187. </template>
  188. </el-table-column>
  189. </el-table>
  190. </div>
  191. <div class="batch-operate-container">
  192. <el-select
  193. size="small"
  194. v-model="operateType" placeholder="批量操作">
  195. <el-option
  196. v-for="item in operates"
  197. :key="item.value"
  198. :label="item.label"
  199. :value="item.value">
  200. </el-option>
  201. </el-select>
  202. <el-button
  203. style="margin-left: 20px"
  204. class="search-button"
  205. @click="handleBatchOperate()"
  206. type="primary"
  207. size="small">
  208. 确定
  209. </el-button>
  210. </div>
  211. <div class="pagination-container">
  212. <el-pagination
  213. background
  214. @size-change="handleSizeChange"
  215. @current-change="handleCurrentChange"
  216. layout="total, sizes,prev, pager, next,jumper"
  217. :page-size="listQuery.pageSize"
  218. :page-sizes="[5,10,15]"
  219. :current-page.sync="listQuery.pageNum"
  220. :total="total">
  221. </el-pagination>
  222. </div>
  223. <el-dialog
  224. title="编辑货品信息"
  225. :visible.sync="editSkuInfo.dialogVisible"
  226. width="40%">
  227. <span>商品货号:</span>
  228. <span>{{editSkuInfo.productSn}}</span>
  229. <el-input placeholder="按sku编号搜索" v-model="editSkuInfo.keyword" size="small" style="width: 50%;margin-left: 20px">
  230. <el-button slot="append" icon="el-icon-search" @click="handleSearchEditSku"></el-button>
  231. </el-input>
  232. <el-table style="width: 100%;margin-top: 20px"
  233. :data="editSkuInfo.stockList"
  234. border>
  235. <el-table-column
  236. label="SKU编号"
  237. align="center">
  238. <template slot-scope="scope">
  239. <el-input v-model="scope.row.skuCode"></el-input>
  240. </template>
  241. </el-table-column>
  242. <el-table-column
  243. v-for="(item,index) in editSkuInfo.productAttr"
  244. :label="item.name"
  245. :key="item.id"
  246. align="center">
  247. <template slot-scope="scope">
  248. {{getProductSkuSp(scope.row,index)}}
  249. </template>
  250. </el-table-column>
  251. <el-table-column
  252. label="销售价格"
  253. width="80"
  254. align="center">
  255. <template slot-scope="scope">
  256. <el-input v-model="scope.row.price"></el-input>
  257. </template>
  258. </el-table-column>
  259. <el-table-column
  260. label="商品库存"
  261. width="80"
  262. align="center">
  263. <template slot-scope="scope">
  264. <el-input v-model="scope.row.stock"></el-input>
  265. </template>
  266. </el-table-column>
  267. <el-table-column
  268. label="库存预警值"
  269. width="100"
  270. align="center">
  271. <template slot-scope="scope">
  272. <el-input v-model="scope.row.lowStock"></el-input>
  273. </template>
  274. </el-table-column>
  275. </el-table>
  276. <span slot="footer" class="dialog-footer">
  277. <el-button @click="editSkuInfo.dialogVisible = false">取 消</el-button>
  278. <el-button type="primary" @click="handleEditSkuConfirm">确 定</el-button>
  279. </span>
  280. </el-dialog>
  281. </div>
  282. </template>
  283. <script>
  284. import {
  285. fetchList,
  286. updateDeleteStatus,
  287. updateNewStatus,
  288. updateRecommendStatus,
  289. updatePublishStatus,
  290. updateVerifyStatus,
  291. } from '@/api/product'
  292. import {fetchList as fetchSkuStockList,update as updateSkuStockList} from '@/api/skuStock'
  293. import {fetchList as fetchProductAttrList} from '@/api/productAttr'
  294. import {fetchList as fetchBrandList} from '@/api/brand'
  295. import {fetchListWithChildren} from '@/api/productCate'
  296. const defaultListQuery = {
  297. keyword: null,
  298. pageNum: 1,
  299. pageSize: 5,
  300. publishStatus: null,
  301. verifyStatus: null,
  302. productSn: null,
  303. productCategoryId: null,
  304. brandId: null
  305. };
  306. export default {
  307. name: "productList",
  308. data() {
  309. return {
  310. editSkuInfo:{
  311. dialogVisible:false,
  312. productId:null,
  313. productSn:'',
  314. productAttributeCategoryId:null,
  315. stockList:[],
  316. productAttr:[],
  317. keyword:null,
  318. },
  319. operates: [
  320. {
  321. label: "商品上架",
  322. value: "publishOn"
  323. },
  324. {
  325. label: "商品下架",
  326. value: "publishOff"
  327. },
  328. {
  329. label: "设为推荐",
  330. value: "recommendOn"
  331. },
  332. {
  333. label: "取消推荐",
  334. value: "recommendOff"
  335. },
  336. {
  337. label: "设为新品",
  338. value: "newOn"
  339. },
  340. {
  341. label: "取消新品",
  342. value: "newOff"
  343. },
  344. {
  345. label: "转移到分类",
  346. value: "transferCategory"
  347. },
  348. {
  349. label: "移入回收站",
  350. value: "recycle"
  351. }
  352. ],
  353. operateType: null,
  354. listQuery: Object.assign({}, defaultListQuery),
  355. list: null,
  356. total: null,
  357. listLoading: true,
  358. selectProductCateValue: null,
  359. multipleSelection: [],
  360. productCateOptions: [],
  361. brandOptions: [],
  362. publishStatusOptions: [{
  363. value: 1,
  364. label: '上架'
  365. }, {
  366. value: 0,
  367. label: '下架'
  368. }],
  369. verifyStatusOptions: [{
  370. value: 1,
  371. label: '审核通过'
  372. }, {
  373. value: 0,
  374. label: '未审核'
  375. }],
  376. permissions:[],
  377. verifyPermission:false,//审核权限
  378. delPermission:false,//删除权限createPermission
  379. updatePermission:false,//编辑权限
  380. createPermission:false,//编辑权限
  381. }
  382. },
  383. created() {
  384. this.getList();
  385. this.getBrandList();
  386. this.getProductCateList();
  387. //权限列表
  388. this.permissions = localStorage.getItem("permissionList").split(',');
  389. console.log('this.permissions',this.permissions);
  390. // verifyPermission
  391. let theverifyPermission = this.permissions.indexOf("/product/update/verify");
  392. if(theverifyPermission>=0){this.verifyPermission=true};
  393. let thedelPermission = this.permissions.indexOf("/update/deleteStatus");
  394. if(thedelPermission>=0){this.delPermission=true};
  395. let theUpdatePermission = this.permissions.indexOf("/product/update/");
  396. if(theUpdatePermission>=0){this.updatePermission=true};
  397. let theCreatePermission = this.permissions.indexOf("/product/create");
  398. if(theCreatePermission>=0){this.createPermission=true};
  399. //权限列表
  400. },
  401. watch: {
  402. selectProductCateValue: function (newValue) {
  403. if (newValue != null && newValue.length == 2) {
  404. this.listQuery.productCategoryId = newValue[1];
  405. } else {
  406. this.listQuery.productCategoryId = null;
  407. }
  408. }
  409. },
  410. filters: {
  411. verifyStatusFilter(value) {
  412. if (value === 1) {
  413. return '审核通过';
  414. } else {
  415. return '未审核';
  416. }
  417. }
  418. },
  419. methods: {
  420. getProductSkuSp(row, index) {
  421. let spData = JSON.parse(row.spData);
  422. if(spData!=null&&index<spData.length){
  423. return spData[index].value;
  424. }else{
  425. return null;
  426. }
  427. },
  428. getList() {
  429. this.listLoading = true;
  430. fetchList(this.listQuery).then(response => {
  431. this.listLoading = false;
  432. this.list = response.data.list;
  433. this.total = response.data.total;
  434. });
  435. },
  436. getBrandList() {
  437. fetchBrandList({pageNum: 1, pageSize: 100}).then(response => {
  438. this.brandOptions = [];
  439. let brandList = response.data.list;
  440. for (let i = 0; i < brandList.length; i++) {
  441. this.brandOptions.push({label: brandList[i].name, value: brandList[i].id});
  442. }
  443. });
  444. },
  445. getProductCateList() {
  446. fetchListWithChildren().then(response => {
  447. let list = response.data;
  448. this.productCateOptions = [];
  449. for (let i = 0; i < list.length; i++) {
  450. let children = [];
  451. if (list[i].children != null && list[i].children.length > 0) {
  452. for (let j = 0; j < list[i].children.length; j++) {
  453. children.push({label: list[i].children[j].name, value: list[i].children[j].id});
  454. }
  455. }
  456. this.productCateOptions.push({label: list[i].name, value: list[i].id, children: children});
  457. }
  458. });
  459. },
  460. handleShowSkuEditDialog(index,row){
  461. this.editSkuInfo.dialogVisible=true;
  462. this.editSkuInfo.productId=row.id;
  463. this.editSkuInfo.productSn=row.productSn;
  464. this.editSkuInfo.productAttributeCategoryId = row.productAttributeCategoryId;
  465. this.editSkuInfo.keyword=null;
  466. fetchSkuStockList(row.id,{keyword:this.editSkuInfo.keyword}).then(response=>{
  467. this.editSkuInfo.stockList=response.data;
  468. });
  469. if(row.productAttributeCategoryId!=null){
  470. fetchProductAttrList(row.productAttributeCategoryId,{type:0}).then(response=>{
  471. this.editSkuInfo.productAttr=response.data.list;
  472. });
  473. }
  474. },
  475. handleSearchEditSku(){
  476. fetchSkuStockList(this.editSkuInfo.productId,{keyword:this.editSkuInfo.keyword}).then(response=>{
  477. this.editSkuInfo.stockList=response.data;
  478. });
  479. },
  480. handleEditSkuConfirm(){
  481. if(this.editSkuInfo.stockList==null||this.editSkuInfo.stockList.length<=0){
  482. this.$message({
  483. message: '暂无sku信息',
  484. type: 'warning',
  485. duration: 1000
  486. });
  487. return
  488. }
  489. this.$confirm('是否要进行修改', '提示', {
  490. confirmButtonText: '确定',
  491. cancelButtonText: '取消',
  492. type: 'warning'
  493. }).then(()=>{
  494. updateSkuStockList(this.editSkuInfo.productId,this.editSkuInfo.stockList).then(response=>{
  495. this.$message({
  496. message: '修改成功',
  497. type: 'success',
  498. duration: 1000
  499. });
  500. this.editSkuInfo.dialogVisible=false;
  501. });
  502. });
  503. },
  504. handleSearchList() {
  505. this.listQuery.pageNum = 1;
  506. this.getList();
  507. },
  508. handleAddProduct() {
  509. this.$router.push({path:'/pms/addProduct'});
  510. },
  511. handleBatchOperate() {
  512. if(this.operateType==null){
  513. this.$message({
  514. message: '请选择操作类型',
  515. type: 'warning',
  516. duration: 1000
  517. });
  518. return;
  519. }
  520. if(this.multipleSelection==null||this.multipleSelection.length<1){
  521. this.$message({
  522. message: '请选择要操作的商品',
  523. type: 'warning',
  524. duration: 1000
  525. });
  526. return;
  527. }
  528. this.$confirm('是否要进行该批量操作?', '提示', {
  529. confirmButtonText: '确定',
  530. cancelButtonText: '取消',
  531. type: 'warning'
  532. }).then(() => {
  533. let ids=[];
  534. for(let i=0;i<this.multipleSelection.length;i++){
  535. ids.push(this.multipleSelection[i].id);
  536. }
  537. switch (this.operateType) {
  538. case this.operates[0].value:
  539. this.updatePublishStatus(1,ids);
  540. break;
  541. case this.operates[1].value:
  542. this.updatePublishStatus(0,ids);
  543. break;
  544. case this.operates[2].value:
  545. this.updateRecommendStatus(1,ids);
  546. break;
  547. case this.operates[3].value:
  548. this.updateRecommendStatus(0,ids);
  549. break;
  550. case this.operates[4].value:
  551. this.updateNewStatus(1,ids);
  552. break;
  553. case this.operates[5].value:
  554. this.updateNewStatus(0,ids);
  555. break;
  556. case this.operates[6].value:
  557. break;
  558. case this.operates[7].value:
  559. this.updateDeleteStatus(1,ids);
  560. break;
  561. default:
  562. break;
  563. }
  564. this.getList();
  565. });
  566. },
  567. handleSizeChange(val) {
  568. this.listQuery.pageNum = 1;
  569. this.listQuery.pageSize = val;
  570. this.getList();
  571. },
  572. handleCurrentChange(val) {
  573. this.listQuery.pageNum = val;
  574. this.getList();
  575. },
  576. handleSelectionChange(val) {
  577. this.multipleSelection = val;
  578. },
  579. handlePublishStatusChange(index, row) {
  580. let ids = [];
  581. ids.push(row.id);
  582. this.updatePublishStatus(row.publishStatus, ids);
  583. },
  584. handleNewStatusChange(index, row) {
  585. let ids = [];
  586. ids.push(row.id);
  587. this.updateNewStatus(row.newStatus, ids);
  588. },
  589. handleRecommendStatusChange(index, row) {
  590. let ids = [];
  591. ids.push(row.id);
  592. this.updateRecommendStatus(row.recommandStatus, ids);
  593. },
  594. handleResetSearch() {
  595. this.selectProductCateValue = [];
  596. this.listQuery = Object.assign({}, defaultListQuery);
  597. },
  598. handleDelete(index, row){
  599. this.$confirm('是否要进行删除操作?', '提示', {
  600. confirmButtonText: '确定',
  601. cancelButtonText: '取消',
  602. type: 'warning'
  603. }).then(() => {
  604. let ids = [];
  605. ids.push(row.id);
  606. this.updateDeleteStatus(1,ids);
  607. });
  608. },
  609. handleUpdateProduct(index,row){
  610. this.$router.push({path:'/pms/updateProduct',query:{id:row.id}});
  611. },
  612. handleShowProduct(index,row){
  613. console.log("handleShowProduct",row);
  614. },
  615. handleShowVerifyDetail(index,row){
  616. console.log("handleShowVerifyDetail",row);
  617. },
  618. handleShowLog(index,row){
  619. console.log("handleShowLog",row);
  620. },
  621. updatePublishStatus(publishStatus, ids) {
  622. let params = new URLSearchParams();
  623. params.append('ids', ids);
  624. params.append('publishStatus', publishStatus);
  625. updatePublishStatus(params).then(response => {
  626. this.$message({
  627. message: '修改成功',
  628. type: 'success',
  629. duration: 1000
  630. });
  631. });
  632. },
  633. updateNewStatus(newStatus, ids) {
  634. let params = new URLSearchParams();
  635. params.append('ids', ids);
  636. params.append('newStatus', newStatus);
  637. updateNewStatus(params).then(response => {
  638. this.$message({
  639. message: '修改成功',
  640. type: 'success',
  641. duration: 1000
  642. });
  643. });
  644. },
  645. updateRecommendStatus(recommendStatus, ids) {
  646. let params = new URLSearchParams();
  647. params.append('ids', ids);
  648. params.append('recommendStatus', recommendStatus);
  649. updateRecommendStatus(params).then(response => {
  650. this.$message({
  651. message: '修改成功',
  652. type: 'success',
  653. duration: 1000
  654. });
  655. });
  656. },
  657. updateDeleteStatus(deleteStatus, ids) {
  658. let params = new URLSearchParams();
  659. params.append('ids', ids);
  660. params.append('deleteStatus', deleteStatus);
  661. updateDeleteStatus(params).then(response => {
  662. this.$message({
  663. message: '删除成功',
  664. type: 'success',
  665. duration: 1000
  666. });
  667. });
  668. this.getList();
  669. },
  670. handleVerify(index,row){
  671. this.$confirm('是否审核通过此产品?', '提示', {
  672. confirmButtonText: '确定',
  673. cancelButtonText: '取消',
  674. type: 'warning'
  675. }).then(() => {
  676. let id = row.id;
  677. updateVerifyStatus(id).then(res => {
  678. this.$message({
  679. message: res.message,
  680. type: 'success',
  681. duration: 1000
  682. });
  683. this.getList();
  684. });
  685. });
  686. // console.log(row)
  687. }
  688. }
  689. }
  690. </script>
  691. <style></style>