goodsList.vue 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557
  1. <template>
  2. <div class="app-container calendar-list-container">
  3. <!-- 查询和其他操作 -->
  4. <div class="filter-container">
  5. <el-input clearable class="filter-item" style="width: 200px;" placeholder="商品名称"
  6. v-model="listQuery.name"></el-input>
  7. <el-input clearable class="filter-item" style="width: 200px;" placeholder="商品编号"
  8. v-model="listQuery.seq"></el-input>
  9. <el-select v-model="listQuery.status" clearable placeholder="状态" class="filter-item" style="width: 200px;">
  10. <el-option :key="item.type" v-for="item in goodsStatusList" :label="item.name" :value="item.type">
  11. </el-option>
  12. </el-select>
  13. <el-select v-model="listQuery.productAttribute" clearable placeholder="商品属性" class="filter-item" style="width: 200px">
  14. <el-option :key="item.dictValue" v-for="item in productAttributeList" :label="item.dictLabel"
  15. :value="item.dictValue">
  16. </el-option>
  17. </el-select>
  18. <el-select v-model="listQuery.deliveryTypes" multiple filterable placeholder="兑换方式" class="filter-item" style="width: 200px">
  19. <el-option :key="item.type" v-for="item in deliveryTypeList" :label="item.name" :value="item.type">
  20. </el-option>
  21. </el-select>
  22. <el-button class="filter-item" type="primary" v-waves icon="el-icon-search" @click="handleFilter">查找</el-button>
  23. <el-button class="filter-item" type="primary" @click="handleCreate" icon="el-icon-edit">添加</el-button>
  24. </div>
  25. <!-- 查询结果 -->
  26. <el-table size="small" :data="list" v-loading="listLoading" element-loading-text="正在查询中。。。" border fit
  27. highlight-current-row>
  28. <el-table-column type="index" label="序号" header-align="center" align="center">
  29. </el-table-column>
  30. <el-table-column align="center" min-width="200px" label="商品名称" prop="name">
  31. </el-table-column>
  32. <el-table-column align="center" min-width="120px" label="商品编号" prop="seq">
  33. </el-table-column>
  34. <el-table-column align="center" min-width="80px" label="商品属性" prop="productAttributeName">
  35. </el-table-column>
  36. <el-table-column align="center" min-width="80px" label="积分" prop="price">
  37. </el-table-column>
  38. <el-table-column align="center" min-width="100px" label="库存量" prop="actualStock">
  39. </el-table-column>
  40. <el-table-column align="center" min-width="100px" label="可兑换库存量" prop="stock">
  41. </el-table-column>
  42. <!-- <el-table-column align="center" min-width="100px" label="商品所在地" prop="location">
  43. </el-table-column> -->
  44. <el-table-column align="center" min-width="80px" label="商品状态">
  45. <template slot-scope="props">
  46. <span v-if="props.row.status == 1">上架</span>
  47. <span v-if="props.row.status == 0">下架</span>
  48. </template>
  49. </el-table-column>
  50. <el-table-column align="center" min-width="80px" label="兑换记录">
  51. <template slot-scope="props">
  52. <span @click="handleView(props.row)" style="color:green;cursor: pointer;">查看</span>
  53. </template>
  54. </el-table-column>
  55. <!-- fixed="right" -->
  56. <el-table-column align="center" label="操作" width="240px" class-name="small-padding fixed-width">
  57. <template slot-scope="scope">
  58. <el-button type="primary" size="small" @click="handleUpdate(scope.row)">编辑</el-button>
  59. <el-button v-if="scope.row.status == 0" type="success" size="small"
  60. @click="changeGoodsState(scope.row.skuId, 1)">上架</el-button>
  61. <el-button v-if="scope.row.status == 1" type="warning" size="small"
  62. @click="changeGoodsState(scope.row.skuId, 0)">下架</el-button>
  63. <el-button type="danger" size="mini" @click="handleDelete(scope.row.skuId, -1)">删除</el-button>
  64. </template>
  65. </el-table-column>
  66. </el-table>
  67. <!-- 分页 -->
  68. <div class="pagination-container">
  69. <el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange"
  70. :current-page="listQuery.page" :page-sizes="[10, 20, 30, 50]" :page-size="listQuery.limit"
  71. layout="total, sizes, prev, pager, next, jumper" :total="total">
  72. </el-pagination>
  73. </div>
  74. <!-- 员工积分记录列表 -->
  75. <el-dialog :close-on-click-modal="false" title="兑换记录" :visible.sync="dialogListVisible" width="70%" style="overflow: auto;">
  76. <div class="filter-container">
  77. <el-select filterable v-model="itemListQuery.deptId" clearable placeholder="部门" style="top: -4px;width: 200px;">
  78. <el-option :key="item.deptId" v-for="item in depTypeList" :label="item.deptName" :value="item.deptId">
  79. </el-option>
  80. </el-select>
  81. <el-input clearable class="filter-item" style="width: 200px;" placeholder="员工名称"
  82. v-model="itemListQuery.userName"></el-input>
  83. <el-button class="filter-item" type="primary" v-waves icon="el-icon-search"
  84. @click="itemHandleFilter">查找</el-button>
  85. <el-button class="filter-item" type="primary" @click="handleDownLoad" v-waves icon="el-icon-download">导出</el-button>
  86. </div>
  87. <!-- 查询结果 -->
  88. <el-table size="small" :data="itemList" v-loading="listLoading" element-loading-text="正在查询中。。。" border fit
  89. highlight-current-row>
  90. <el-table-column type="index" label="序号" header-align="center" align="center">
  91. </el-table-column>
  92. <el-table-column align="center" width="200px" label="部门" prop="deptName">
  93. </el-table-column>
  94. <el-table-column align="center" label="员工姓名" prop="purchaser">
  95. </el-table-column>
  96. <el-table-column align="center" label="兑换数量" prop="skuCount">
  97. </el-table-column>
  98. <el-table-column align="center" label="联系人" prop="contact">
  99. </el-table-column>
  100. <el-table-column align="center" width="120px" label="联系方式" prop="contactPhone">
  101. </el-table-column>
  102. <el-table-column align="center" width="200px" label="地址" prop="contactAddr">
  103. </el-table-column>
  104. <!-- <el-table-column align="center" width="200px" label="邮箱" prop="contactEmail">
  105. </el-table-column> -->
  106. <el-table-column align="center" width="150px" label="兑换时间" prop="createTime">
  107. </el-table-column>
  108. </el-table>
  109. <!-- 分页 -->
  110. <div class="pagination-container">
  111. <el-pagination background @size-change="itemHandleSizeChange" @current-change="itemHandleCurrentChange"
  112. :current-page="itemListQuery.page" :page-sizes="[10, 20, 30, 50]" :page-size="itemListQuery.limit"
  113. layout="total, sizes, prev, pager, next, jumper" :total="itemTotal">
  114. </el-pagination>
  115. </div>
  116. </el-dialog>
  117. <!-- 添加或修改对话框 -->
  118. <el-dialog :close-on-click-modal="false" :title="textMap[dialogStatus]" :visible.sync="dialogFormVisible" width="70%">
  119. <el-form :rules="rules" ref="dataForm" :model="dataForm" status-icon label-position="left" label-width="100px" style='width:700px; margin-left:50px;'>
  120. <el-form-item label="商品编号" prop="seq">
  121. <el-input disabled placeholder="添加成功后自动生成" readonly v-model="dataForm.seq"></el-input>
  122. </el-form-item>
  123. <el-form-item label="商品名称" prop="name">
  124. <el-input v-model="dataForm.name"></el-input>
  125. </el-form-item>
  126. <el-form-item label="商品属性" prop="productAttribute">
  127. <el-select v-model="dataForm.productAttribute" filterable placeholder="请选择" style="width: 350px"
  128. value-key="value" @change="changeProductAttribute">
  129. <el-option :key="item.dictValue" v-for="item in productAttributeList" :label="item.dictLabel"
  130. :value="item.dictValue">
  131. </el-option>
  132. </el-select>
  133. </el-form-item>
  134. <el-form-item label="兑换方式" prop="deliveryTypes">
  135. <el-select v-model="dataForm.deliveryTypes" multiple filterable placeholder="请选择" style="width: 350px">
  136. <el-option :key="item.dictValue" v-for="item in deliveryTypeList" :label="item.dictLabel" :value="item.dictValue">
  137. </el-option>
  138. </el-select>
  139. </el-form-item>
  140. <!-- <el-form-item v-if="dataForm.deliveryTypes==0" label="商品所在地" prop="location">
  141. <el-select v-model="dataForm.location" filterable placeholder="请选择" style="width: 350px">
  142. <el-option :key="item.dictLabel" v-for="item in locationList" :label="item.dictLabel" :value="item.dictLabel">
  143. </el-option>
  144. </el-select>
  145. </el-form-item> -->
  146. <el-form-item style="width: 800px" label="商品图片" prop="imgUrl">
  147. <el-upload :limit="1" :action="fileImgUrl" list-type="picture-card" :file-list="dataForm.images"
  148. :on-success="handleGallerySucess" :on-exceed="handleExceed" :before-upload="uploadBannerImg"
  149. :on-remove="handleRemove">
  150. <i class="el-icon-plus"></i>
  151. </el-upload>
  152. </el-form-item>
  153. <el-form-item label="积分" prop="price">
  154. <el-input v-model="dataForm.price"></el-input>
  155. </el-form-item>
  156. <el-form-item label="库存量" prop="actualStock">
  157. <el-input-number :precision="0" :step="1" v-model="dataForm.actualStock"></el-input-number>
  158. </el-form-item>
  159. <el-form-item
  160. style="width: 800px"
  161. label="商品说明"
  162. prop="comment"
  163. >
  164. <tinymce v-model="dataForm.comment" ref="tinymce"></tinymce>
  165. </el-form-item>
  166. </el-form>
  167. <div slot="footer" class="dialog-footer">
  168. <el-button @click="dialogFormVisible = false">取消</el-button>
  169. <el-button v-if="dialogStatus == 'create'" type="primary" @click="createData">确定</el-button>
  170. <el-button v-else type="primary" @click="updateData">确定</el-button>
  171. </div>
  172. </el-dialog>
  173. </div>
  174. </template>
  175. <style>
  176. .demo-table-expand {
  177. font-size: 0;
  178. }
  179. .demo-table-expand label {
  180. width: 200px;
  181. color: #99a9bf;
  182. }
  183. .demo-table-expand .el-form-item {
  184. margin-right: 0;
  185. margin-bottom: 0;
  186. }
  187. </style>
  188. <script>
  189. import { createItem, updateItem, goodsList, goodsState, exchangeHistory } from "@/api/goodsManage";
  190. import { depTypeList,dataTypeList } from "@/api/public";
  191. import waves from "@/directive/waves"; // 水波纹指令
  192. import Tinymce from '@/components/Tinymce'
  193. export default {
  194. name: 'goodsList',
  195. components: { Tinymce },
  196. directives: { waves },
  197. data() {
  198. return {
  199. locationList:[],
  200. productAttributeList: [],
  201. deliveryTypeList: [],
  202. goodsStatusList: [
  203. {
  204. type: 1,
  205. name: '上架'
  206. },
  207. {
  208. type: 0,
  209. name: '下架'
  210. },
  211. ],
  212. depTypeList: [],
  213. list: [],
  214. itemList: [],
  215. total: 0,
  216. itemTotal: 0,
  217. listLoading: false,
  218. downloadLoading: false,
  219. listQuery: {
  220. page: 1,
  221. limit: 10,
  222. name: '',
  223. seq: '',
  224. status: '',
  225. productAttribute:'',
  226. },
  227. itemListQuery: {
  228. page: 1,
  229. limit: 10,
  230. skuId:'',
  231. deptId: '',
  232. userName: '',
  233. },
  234. dataForm: {
  235. name: undefined,
  236. seq: undefined,
  237. productAttribute: undefined,
  238. imgUrl: undefined,
  239. price: undefined,
  240. actualStock: undefined,
  241. deliveryTypes: [],
  242. // location: undefined,
  243. images: [],
  244. },
  245. dialogFormVisible: false,
  246. dialogStatus: '',
  247. textMap: {
  248. update: "编辑",
  249. create: "创建",
  250. },
  251. rules: {
  252. name: [{ required: true, message: "请填写商品名称", trigger: "blur" }],
  253. imgUrl: [{ required: true, message: "请上传商品图片", trigger: "blur" }],
  254. productAttribute: [{ required: true, message: "请选择商品属性", trigger: "blur" }],
  255. price: [{ required: true, message: "请填写商品积分", trigger: "blur" }],
  256. actualStock: [{ required: true, message: "请设置库存量", trigger: "blur" }],
  257. deliveryTypes: [{ required: true, message: "请选择兑换方式", trigger: "blur" }],
  258. // location: [{ required: true, message: "请选择商品所在地", trigger: "blur" }],
  259. comment: [{ required: true, message: "说明不能为空", trigger: "blur" }],
  260. },
  261. dialogListVisible: false,
  262. fileImgUrl: this.upLoadUrl,
  263. }
  264. },
  265. created() {
  266. this.getProductAttributeList();
  267. this.getDataTypeList();
  268. this.getDepTypeList();
  269. this.getList();
  270. },
  271. methods: {
  272. getDeliveryTypeList(val){
  273. dataTypeList({dictType:val}).then(response => {
  274. this.deliveryTypeList = response.data.data;
  275. });
  276. },
  277. handleDownLoad(){
  278. window.location.href = process.env.BASE_API + '/mall-sku/exportSkuLog?skuId=' + this.itemListQuery.skuId + '&deptId=' + this.itemListQuery.deptId + '&userName=' + this.itemListQuery.userName;
  279. },
  280. changeProductAttribute(val) {
  281. debugger
  282. this.dataForm.deliveryTypes = [];
  283. // this.dataForm.location = undefined;
  284. this.getDeliveryTypeList(val);
  285. },
  286. handleRemove(file, fileList) {
  287. console.log(file, fileList);
  288. let images = [];
  289. for (let i in fileList) {
  290. let response = fileList[i].response;
  291. let url = response.data.url;
  292. images.push(url);
  293. this.dataForm.imgUrl = images.join(",");
  294. }
  295. },
  296. uploadBannerImg(file) {
  297. const isJPGs = file.type === "image/jpeg";
  298. console.log(isJPGs);
  299. },
  300. handleExceed(files, fileList) {
  301. this.$message.warning(
  302. `当前限制选择 1 个文件,本次选择了 ${files.length} 个文件!,共选择了 ${files.length + fileList.length
  303. } 个文件`
  304. );
  305. },
  306. handleGallerySucess(res, file, fileList) {
  307. this.dataForm.imgUrl = ""; // 清空画廊图片数组
  308. let images = [];
  309. for (let i in fileList) {
  310. let response = fileList[i].response;
  311. if (response.errno && response.errno != "0") {
  312. this.$message.error("该图片上传失败,已被移除,请重新上传!");
  313. // 上传失败移除该 file 对象
  314. fileList.splice(i, 1);
  315. } else {
  316. let url = response.data.url;
  317. images.push(url);
  318. }
  319. }
  320. this.dataForm.imgUrl = images.join(",");
  321. },
  322. resetForm() {
  323. this.dataForm = {
  324. comment: undefined,
  325. name: undefined,
  326. seq: undefined,
  327. productAttribute: undefined,
  328. imgUrl: undefined,
  329. price: undefined,
  330. actualStock: undefined,
  331. deliveryTypes: [],
  332. // location: undefined,
  333. images: [],
  334. };
  335. },
  336. handleCreate() {
  337. this.resetForm();
  338. this.dialogFormVisible = true;
  339. this.dialogStatus = "create";
  340. this.$nextTick(() => {
  341. this.$refs.tinymce.setContent("");
  342. this.$refs["dataForm"].clearValidate();
  343. });
  344. },
  345. createData() {
  346. this.$refs["dataForm"].validate((valid) => {
  347. if (valid) {
  348. console.log(this.dataForm);
  349. createItem(this.dataForm)
  350. .then((response) => {
  351. this.getList();
  352. this.dialogFormVisible = false;
  353. this.$notify({
  354. title: "成功",
  355. message: "创建成功",
  356. type: "success",
  357. duration: 2000,
  358. });
  359. this.reload();
  360. })
  361. .catch(() => { });
  362. }
  363. });
  364. },
  365. handleUpdate(row) {
  366. this.dataForm = Object.assign({}, row);
  367. this.dataForm.productAttribute = row.productAttribute.toString();
  368. let comment = this.dataForm.comment;
  369. let val = row.productAttribute;
  370. this.getDeliveryTypeList(val);
  371. if (this.dataForm.imgUrl) {
  372. let images = this.dataForm.imgUrl.split(",");
  373. this.dataForm.images = [];
  374. for (let i in images) {
  375. let url = images[i];
  376. let name = "image_" + i;
  377. this.dataForm.images.push({
  378. name: name,
  379. url: url,
  380. response: { error: "0", data: { url: url } },
  381. });
  382. }
  383. }
  384. this.dialogStatus = 'update'
  385. this.dialogFormVisible = true
  386. this.$nextTick(() => {
  387. this.$refs.tinymce.setContent(comment);
  388. this.$refs['dataForm'].clearValidate()
  389. })
  390. },
  391. updateData() {
  392. this.$refs['dataForm'].validate((valid) => {
  393. if (valid) {
  394. updateItem(this.dataForm).then(() => {
  395. this.dialogFormVisible = false
  396. this.$notify({
  397. title: '成功',
  398. message: '更新成功',
  399. type: 'success',
  400. duration: 2000
  401. })
  402. this.getList()
  403. })
  404. }
  405. })
  406. },
  407. changeGoodsState(id, index) {
  408. goodsState({ skuId: id, status: index }).then(response => {
  409. this.$notify({
  410. title: '成功',
  411. message: '商品状态修改成功',
  412. type: 'success',
  413. duration: 2000
  414. })
  415. this.getList()
  416. })
  417. },
  418. handleDelete(id, index) {
  419. this.$confirm('确认删除吗?', '提示', {
  420. confirmButtonText: '确定',
  421. cancelButtonText: '取消',
  422. type: 'warning'
  423. }).then(() => {
  424. goodsState({ skuId: id, status: index }).then(response => {
  425. this.$notify({
  426. title: '成功',
  427. message: '删除成功',
  428. type: 'success',
  429. duration: 2000
  430. })
  431. this.getList();
  432. })
  433. }).catch(() => {
  434. })
  435. },
  436. getDataTypeList() {
  437. dataTypeList({dictType:'mall_sku_location'}).then(response => {
  438. this.locationList = response.data.data;
  439. }).catch(() => {});
  440. },
  441. getProductAttributeList(){
  442. dataTypeList({dictType:'mall_sku_attribute'}).then(response => {
  443. this.productAttributeList = response.data.data;
  444. }).catch(() => {});
  445. },
  446. getDepTypeList() {
  447. depTypeList().then(response => {
  448. this.depTypeList = response.data.data;
  449. }).catch(() => {});
  450. },
  451. getList() {
  452. this.listLoading = true
  453. goodsList(this.listQuery).then(response => {
  454. this.list = response.data.data.items
  455. this.total = response.data.data.total
  456. this.listLoading = false
  457. }).catch(() => {})
  458. },
  459. getItemList() {
  460. this.listLoading = true
  461. exchangeHistory(this.itemListQuery).then(response => {
  462. this.itemList = response.data.data.items
  463. this.itemLotal = response.data.data.total
  464. this.listLoading = false
  465. }).catch(() => {})
  466. },
  467. handleFilter() {
  468. this.listQuery.page = 1
  469. this.getList()
  470. },
  471. handleSizeChange(val) {
  472. this.listQuery.limit = val
  473. this.getList()
  474. },
  475. handleCurrentChange(val) {
  476. this.listQuery.page = val
  477. this.getList()
  478. },
  479. itemHandleFilter() {
  480. this.itemListQuery.page = 1
  481. this.getItemList()
  482. },
  483. itemHandleSizeChange(val) {
  484. this.itemListQuery.limit = val
  485. this.getItemList()
  486. },
  487. itemHandleCurrentChange(val) {
  488. this.itemListQuery.page = val
  489. this.getItemList()
  490. },
  491. handleView(row) {
  492. this.itemListQuery.skuId = row.skuId;
  493. this.getItemList();
  494. this.dialogListVisible = true
  495. },
  496. }
  497. }
  498. </script>
  499. <style>
  500. .ad-avatar-uploader .el-upload {
  501. border: 1px dashed #d9d9d9;
  502. border-radius: 6px;
  503. cursor: pointer;
  504. position: relative;
  505. overflow: hidden;
  506. }
  507. .ad-avatar-uploader .el-upload:hover {
  508. border-color: #409EFF;
  509. }
  510. .ad-avatar-uploader-icon {
  511. font-size: 28px;
  512. color: #8c939d;
  513. width: 178px;
  514. height: 178px;
  515. line-height: 178px;
  516. text-align: center;
  517. }
  518. .ad-avatar {
  519. display: block;
  520. }
  521. </style>