index.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  1. <template>
  2. <div class="app-container coupon-list">
  3. <el-form v-show="showSearch" :model="queryParams" ref="queryForm" :inline="true" size="small">
  4. <el-form-item label="商品名称" prop="title">
  5. <el-input
  6. v-model="queryParams.title"
  7. placeholder="请输入商品名称"
  8. clearable
  9. @clear="queryParams.pageNum = 1;getList()"
  10. @keyup.enter.native="queryParams.pageNum = 1;getList()"
  11. />
  12. </el-form-item>
  13. <el-form-item label="商品ID" prop="goodsId">
  14. <el-input
  15. v-model="queryParams.goodsId"
  16. placeholder="请输入商品ID"
  17. clearable
  18. @clear="queryParams.pageNum = 1;getList()"
  19. @keyup.enter.native="queryParams.pageNum = 1;getList()"
  20. />
  21. </el-form-item>
  22. <el-form-item label="商品类型" prop="type">
  23. <el-select v-model="queryParams.type" placeholder="请选择是否支持兑换" clearable
  24. @change="queryParams.pageNum = 1;getList()">
  25. <el-option label="全部" value=""/>
  26. <el-option label="实物商品" value="1"/>
  27. <el-option label="卡密商品" value="2"/>
  28. </el-select>
  29. </el-form-item>
  30. <el-form-item label="商品分类" prop="categoryIdList">
  31. <el-cascader
  32. v-model="queryParams.categoryIdList" collapse-tags clearable
  33. :options="goodsCategoryItemsList"
  34. :props="{ expandTrigger: 'hover', value: 'categoryId',label: 'name', children: 'goodsCategoryList', multiple: true, }"
  35. @change="queryParams.pageNum = 1;getList()"></el-cascader>
  36. </el-form-item>
  37. <el-form-item label="商品标签" prop="tagId">
  38. <el-select
  39. v-model="queryParams.tagId"
  40. placeholder="请选择商品标签"
  41. clearable
  42. @change="queryParams.pageNum = 1;getList()"
  43. >
  44. <el-option :label="item.name" :value="item.tagId" v-for="(item, index) in goodsTagItemsList" :key="index"/>
  45. </el-select>
  46. </el-form-item>
  47. <el-form-item label="上架状态" prop="status">
  48. <el-select v-model="queryParams.status" placeholder="请选择商品状态" clearable
  49. @change="queryParams.pageNum = 1;getList()">
  50. <el-option label="全部" value=""/>
  51. <el-option label="待上架" value="init"/>
  52. <el-option label="已上架" value="on"/>
  53. <el-option label="已下架" value="off"/>
  54. </el-select>
  55. </el-form-item>
  56. <el-form-item label="是否支持兑换" prop="exchangeShow">
  57. <el-select v-model="queryParams.exchangeShow" placeholder="请选择是否支持兑换" clearable
  58. @change="queryParams.pageNum = 1;getList()">
  59. <el-option label="全部" value=""/>
  60. <el-option label="支持兑换" value="1"/>
  61. <el-option label="不支持兑换" value="0"/>
  62. <el-option label="盲票商品" value="2"/>
  63. </el-select>
  64. </el-form-item>
  65. <el-form-item label="供应商" prop="supplierId">
  66. <el-select v-model="queryParams.supplierId" placeholder="请选择供应商" filterable clearable
  67. @clear="queryParams.pageNum = 1;getList()" @change="queryParams.pageNum = 1;getList()">
  68. <el-option :label="item.name" :value="item.id" v-for="(item, index) in SupplierList" :key="index"/>
  69. </el-select>
  70. </el-form-item>
  71. <br>
  72. <el-form-item label="商品成本" prop="minCost">
  73. <el-input v-model="queryParams.minCost" placeholder="最低成本" clearable
  74. @keyup.enter.native="queryParams.pageNum = 1;getList()"/>
  75. </el-form-item>
  76. <el-form-item label="-" prop="maxCost">
  77. <el-input v-model="queryParams.maxCost" placeholder="最高成本" clearable
  78. @keyup.enter.native="queryParams.pageNum = 1;getList()"/>
  79. </el-form-item>
  80. <el-form-item label="价格" prop="minValue">
  81. <el-input v-model="queryParams.minValue" placeholder="最低价格" clearable
  82. @keyup.enter.native="queryParams.pageNum = 1;getList()"/>
  83. </el-form-item>
  84. <el-form-item label="-" prop="maxValue">
  85. <el-input v-model="queryParams.maxValue" placeholder="最高价格" clearable
  86. @keyup.enter.native="queryParams.pageNum = 1;getList()"/>
  87. </el-form-item>
  88. <el-form-item>
  89. <el-button type="primary" icon="el-icon-search" @click="queryParams.pageNum = 1;getList()">搜索</el-button>
  90. <el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
  91. </el-form-item>
  92. </el-form>
  93. <el-row :gutter="10" class="mb8">
  94. <el-col :span="1.5">
  95. <el-button v-hasPermi="['business:goods:add']" type="primary" icon="el-icon-plus" size="mini"
  96. @click="$router.push({ name: 'GoodsAdd' })">添加商品
  97. </el-button>
  98. <!-- <el-button v-hasPermi="['business:goods:on']" type="primary" plain size="mini">上架</el-button> -->
  99. <!-- <el-button v-hasPermi="['business:goods:off']" type="primary" plain size="mini">下架</el-button> -->
  100. <!-- <el-button v-hasPermi="['business:goods:remove']" type="danger" plain size="mini">删除</el-button> -->
  101. </el-col>
  102. <el-col :span="1.5">
  103. <el-button
  104. type="infor"
  105. plain
  106. icon="el-icon-download"
  107. size="mini"
  108. @click="handleOrderExport"
  109. v-hasPermi="['business:goods:export']"
  110. >导出商品
  111. </el-button>
  112. </el-col>
  113. <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
  114. </el-row>
  115. <el-table v-loading="loading" :data="tableData" @sort-change="sortChannelId">
  116. <el-table-column label="商品ID" prop="goodsId" width="60"/>
  117. <el-table-column label="商品图片" prop="picUrl" align="center">
  118. <template slot-scope="{row}">
  119. <div v-if="row.picUrl">
  120. <el-image
  121. style="width: 100px; height: 100px"
  122. :src="IMG_URL + row.picUrl.split(',')[0]"
  123. :preview-src-list="row.picUrl.split(',').map(item => { return IMG_URL + item })"
  124. />
  125. </div>
  126. <span v-else>-</span>
  127. </template>
  128. </el-table-column>
  129. <el-table-column label="商品名称" prop="title"/>
  130. <el-table-column label="价格" prop="value" sortable="custom">
  131. <template slot-scope="{row}">
  132. ¥{{ $numberFormat(row.value) }}
  133. </template>
  134. </el-table-column>
  135. <el-table-column label="商品成本" prop="cost" sortable="custom" min-width="100px">
  136. <template slot-scope="{row}">
  137. ¥{{ $numberFormat(row.cost) }}
  138. </template>
  139. </el-table-column>
  140. <el-table-column label="是否支持兑换" prop="exchangeShow" min-width="100px">
  141. <template slot-scope="{row}">
  142. <span v-if="row.exchangeShow == '1'">支持</span>
  143. <span v-if="row.exchangeShow == '0'">不支持</span>
  144. <span v-if="row.exchangeShow == '2'">盲票商品</span>
  145. </template>
  146. </el-table-column>
  147. <el-table-column label="商品类型" prop="type" min-width="100px">
  148. <template slot-scope="{row}">
  149. <span v-if="row.type == '1'">实物商品</span>
  150. <span v-if="row.type == '2'">卡密商品</span>
  151. </template>
  152. </el-table-column>
  153. <el-table-column label="盲豆兑换数量" prop="exchangePrice" sortable="custom" min-width="125"/>
  154. <el-table-column label="销量" prop="exchangedQty" sortable="custom"/>
  155. <el-table-column label="库存" prop="quantity" sortable="custom"/>
  156. <el-table-column label="状态" prop="status">
  157. <template slot-scope="{row}">
  158. <el-tag :type="JSON.parse(row.status).value === 'on' ? 'success' : 'info'">{{
  159. JSON.parse(row.status).desc
  160. }}
  161. </el-tag>
  162. </template>
  163. </el-table-column>
  164. <el-table-column label="排序" prop="sortWeight" sortable="custom" align="center" width="140px">
  165. <template slot-scope="{row, $index}">
  166. <el-input-number v-model="row.sortWeight" @change="handleSortChange($index,row.sortWeight)"
  167. controls-position="right" size="small"></el-input-number>
  168. </template>
  169. </el-table-column>
  170. <el-table-column fixed="right" align="center" label="操作" width="140">
  171. <template slot-scope="{row}">
  172. <!-- <el-button v-hasPermi="['business:goods:query']" type="text">查看</el-button> -->
  173. <el-button v-hasPermi="['business:goods:edit']" type="text" @click="handleCamilo(row.goodsId)" v-if="row.type === 2">
  174. 查看卡密
  175. </el-button>
  176. <el-button v-hasPermi="['business:goods:edit']" type="text" @click="handleImport(row.goodsId)"
  177. v-if="row.type === 2">添加卡密
  178. </el-button>
  179. <el-button v-hasPermi="['business:goods:edit']" type="text"
  180. @click="$router.push({ name: 'GoodsEdit', query: { id: row.goodsId } })">编辑
  181. </el-button>
  182. <el-button v-if="JSON.parse(row.status).value === 'off' || JSON.parse(row.status).value === 'init'"
  183. v-hasPermi="['business:goods:on']" type="text" @click="setStatus(row, 'on')">上架
  184. </el-button>
  185. <el-button v-if="JSON.parse(row.status).value === 'on'" v-hasPermi="['business:goods:off']" type="text"
  186. @click="setStatus(row, 'off')">下架
  187. </el-button>
  188. <el-button v-if="JSON.parse(row.status).value === 'init'" v-hasPermi="['business:coupon:remove']" class="del"
  189. type="text" @click="del(row)">删除
  190. </el-button>
  191. </template>
  192. </el-table-column>
  193. </el-table>
  194. <pagination :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize"
  195. @pagination="getList()"/>
  196. <!-- 查看卡密-->
  197. <camilo v-if="camiloShow" @cancel="cancel" :camiloShow="camiloShow" :camiloGoodsId="camiloGoodsId"></camilo>
  198. <!-- 导入卡密-->
  199. <el-dialog :title="upload.title" :visible.sync="upload.open" width="400px" append-to-body :before-close="openSwitch">
  200. 1.请下载Excel模版,填写卡密
  201. <br><br>
  202. &emsp;&emsp;<a style="color: #1890FF;" @click="downloadExcel">下载Excel模版</a>
  203. <br><br>
  204. 2.上传填写好卡密的Excel
  205. <div style="padding-top: 20px; text-align: center">
  206. <el-upload
  207. ref="upload"
  208. :limit="1"
  209. :data="reqData"
  210. accept=".xlsx, .xls"
  211. :headers="upload.headers"
  212. :action="upload.url"
  213. :disabled="upload.isUploading"
  214. :on-progress="handleFileUploadProgress"
  215. :on-success="handleFileSuccess"
  216. :auto-upload="false"
  217. :http-request="reqUploadFile"
  218. :on-exceed="exceedMax"
  219. drag
  220. >
  221. <i class="el-icon-upload"></i>
  222. <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
  223. <div class="el-upload__tip text-center" slot="tip">
  224. <span>仅允许导入 xls xlsx 格式文件。</span>
  225. </div>
  226. </el-upload>
  227. </div>
  228. <div slot="footer" class="dialog-footer">
  229. <el-button @click="openSwitch()">取 消</el-button>
  230. <el-button type="primary" @click="submitFileForm">确 定</el-button>
  231. </div>
  232. </el-dialog>
  233. </div>
  234. </template>
  235. <script>
  236. import Camilo from '@/components/Camilo'
  237. import {publicFileGetUrl} from "@/api/common"
  238. import {
  239. getGoodsList,
  240. delGoods,
  241. setGoodsStatus,
  242. setTableData,
  243. salesiteGoodsExport,
  244. setCamiloShip, cradDownload
  245. } from '@/api/business/goods'
  246. import {goodsCategoryListTree} from '@/api/business/category'
  247. import {goodsTagItems} from '@/api/business/tag'
  248. import {accMul} from '@/utils/util'
  249. import {getSupplierList} from '@/api/business/supplier'
  250. import {randomStr20} from '@/utils/util'
  251. import {getToken, getSign} from "@/utils/auth";
  252. export default {
  253. name: 'List',
  254. components: {
  255. Camilo
  256. },
  257. data() {
  258. return {
  259. IMG_URL: publicFileGetUrl,
  260. loading: false,
  261. showSearch: true,
  262. queryParams: {pageNum: 1, pageSize: 10, orderByColumn: '', isAsc: '',},
  263. tableData: [],
  264. total: 0,
  265. goodsCategoryItemsList: [],
  266. goodsTagItemsList: [],
  267. SupplierList: [],
  268. camiloShow: false,
  269. // 用户导入参数
  270. upload: {
  271. open: false,// 是否显示弹出层(用户导入)
  272. title: "",// 弹出层标题(用户导入)
  273. isUploading: false,// 是否禁用上传
  274. url: "",// 上传的地址
  275. headers: {},//请求头
  276. },
  277. reqData: {},
  278. camiloGoodsId: null,
  279. }
  280. },
  281. created() {
  282. this.getList(true)
  283. this.getGoodsCategoryItems()
  284. this.getGoodsTagItems()
  285. this.getSupplierItems()
  286. },
  287. methods: {
  288. //获取供应商
  289. getSupplierItems() {
  290. getSupplierList('', {}).then(res => {
  291. this.SupplierList = res && res.rows
  292. })
  293. },
  294. //切换排序
  295. sortChannelId(row) {
  296. if (row) {
  297. let prop = row.prop == 'commRate' ? ('t1.' + row.prop) : row.prop;
  298. this.queryParams.orderByColumn = prop
  299. this.queryParams.isAsc = row.order == 'ascending' ? "asc" : "desc";
  300. this.getList()
  301. }
  302. },
  303. //步进器修改
  304. handleSortChange(index, sortWeight) {
  305. this.tableData[index].sortWeight = sortWeight
  306. let data = {
  307. goodsId: this.tableData[index].goodsId,
  308. sortWeight: this.tableData[index].sortWeight
  309. }
  310. setTableData(data)
  311. },
  312. //取消查看卡密
  313. cancel() {
  314. this.camiloShow = false
  315. },
  316. //下载excel模版表格
  317. downloadExcel() {
  318. cradDownload().then(response => {
  319. this.download(response.msg);
  320. })
  321. },
  322. //查看卡密
  323. handleCamilo(id){
  324. this.camiloGoodsId = id
  325. this.camiloShow = true
  326. },
  327. //上传卡密按钮操作
  328. handleImport(id) {
  329. this.camiloGoodsId = id
  330. this.upload.title = "添加卡密";
  331. this.upload.open = true;
  332. this.getHttpHeader(id)
  333. },
  334. // 文件上传中处理
  335. handleFileUploadProgress(event, file, fileList) {
  336. this.upload.isUploading = true;
  337. },
  338. // 文件上传成功处理
  339. handleFileSuccess(response, file, fileList) {
  340. this.upload.open = false;
  341. this.upload.isUploading = false;
  342. this.getList();
  343. },
  344. // 超出限制时的提示
  345. exceedMax() {
  346. this.$message({
  347. message: '请移除已有文件后再进行上传',
  348. type: 'warning'
  349. })
  350. },
  351. openSwitch() {
  352. this.upload.open = false
  353. this.$refs.upload.clearFiles();
  354. },
  355. // 提交上传文件
  356. submitFileForm() {
  357. this.$refs.upload.submit();
  358. },
  359. //请求头
  360. getHttpHeader(id) {
  361. let timestamp = parseInt(new Date().getTime()),
  362. nonce = randomStr20();
  363. var sign = getSign(this.reqData || {}, timestamp)
  364. let url = process.env.VUE_APP_BASE_API + `/api/v1/mp/admin/goods/card/import/${id}` + '?sign=' + sign + '&nonce=' + nonce;
  365. this.upload.url = url
  366. var headers = {
  367. "Authorization": "Bearer " + getToken(),
  368. "x-zz-timestamp": timestamp
  369. }
  370. this.upload.headers = headers
  371. },
  372. // 自定义文件上传的实现
  373. reqUploadFile(param) {
  374. var data = this.reqData || {}
  375. var params = {
  376. file: param.file,
  377. ...data
  378. }
  379. this.vloading = this.$loading({
  380. lock: true,
  381. text: "正在导入卡密.....",
  382. background: "rgba(0, 0, 0, 0.7)",
  383. });
  384. setCamiloShip(params, this.headers, this.camiloGoodsId).then(response => {
  385. this.vloading.close();
  386. this.upload.open = false;
  387. this.upload.isUploading = false;
  388. this.$refs.upload.clearFiles();
  389. this.$message({
  390. message: '导入成功',
  391. type: 'success'
  392. })
  393. }).catch(() => {
  394. this.vloading.close();
  395. })
  396. },
  397. getGoodsCategoryItems() {
  398. goodsCategoryListTree("", {}).then(res => {
  399. this.goodsCategoryItemsList = res && res.rows
  400. })
  401. },
  402. getGoodsTagItems() {
  403. goodsTagItems({}).then(res => {
  404. this.goodsTagItemsList = res && res.data
  405. })
  406. },
  407. getList(reset) {
  408. if (this.loading) {
  409. return
  410. }
  411. this.loading = true
  412. // if (reset) {
  413. // this.queryParams = { pageNum: 1, pageSize: 20, orderByColumn: '', isAsc: '', }
  414. // }
  415. if (this.queryParams.categoryIdList) {
  416. for (let i = 0; i < this.queryParams.categoryIdList.length; i++) {
  417. if (this.queryParams.categoryIdList[i][1]) {
  418. this.queryParams.categoryIdList[i] = this.queryParams.categoryIdList[i][1]
  419. }
  420. }
  421. }
  422. getGoodsList('pageNum=' + this.queryParams.pageNum + '&pageSize=' + this.queryParams.pageSize + '&orderByColumn=' + this.queryParams.orderByColumn + '&isAsc=' + this.queryParams.isAsc + '&', {
  423. title: this.queryParams.title,
  424. goodsId: this.queryParams.goodsId,
  425. type: this.queryParams.type ? Number(this.queryParams.type) : this.queryParams.type,
  426. categoryIdList: this.queryParams.categoryIdList,
  427. tagId: this.queryParams.tagId,
  428. status: this.queryParams.status,
  429. exchangeShow: this.queryParams.exchangeShow, supplierId: this.queryParams.supplierId,
  430. minCost: this.queryParams.minCost ? accMul(this.queryParams.minCost, 100) : this.queryParams.minCost,
  431. maxCost: this.queryParams.maxCost ? accMul(this.queryParams.maxCost, 100) : this.queryParams.maxCost,
  432. minValue: this.queryParams.minValue ? accMul(this.queryParams.minValue, 100) : this.queryParams.minValue,
  433. maxValue: this.queryParams.maxValue ? accMul(this.queryParams.maxValue, 100) : this.queryParams.maxValue
  434. }).then(res => {
  435. this.loading = false
  436. if (res.code === 0) {
  437. this.tableData = res.rows
  438. // this.tableData.map()
  439. this.total = res.total
  440. }
  441. }).catch(() => {
  442. this.loading = false
  443. })
  444. },
  445. // 重置
  446. resetQuery() {
  447. this.queryParams = {pageNum: 1, pageSize: 10, orderByColumn: '', isAsc: '',}
  448. this.getList();
  449. },
  450. setStatus(item, status) {
  451. this.$confirm(`确认${status === 'on' ? '上架' : '下架'}商品 “${item.title}” 吗?`, `${status === 'on' ? '上架' : '下架'}商品`, {
  452. confirmButtonText: '确定',
  453. cancelButtonText: '取消',
  454. type: 'warning'
  455. }).then(() => {
  456. setGoodsStatus({
  457. goodsId: item.goodsId,
  458. status
  459. }).then(res => {
  460. if (res.code === 0) {
  461. this.$message.success('操作已完成!')
  462. this.getList()
  463. }
  464. })
  465. })
  466. },
  467. // 导出商品
  468. handleOrderExport() {
  469. this.$confirm("是否确认导出商品?", "提示", {
  470. confirmButtonText: "确定",
  471. cancelButtonText: "取消",
  472. type: "warning",
  473. })
  474. .then(() => {
  475. this.vloading = this.$loading({
  476. lock: true,
  477. text: "正在导出商品.....",
  478. background: "rgba(0, 0, 0, 0.7)",
  479. });
  480. return salesiteGoodsExport(this.queryParams);
  481. })
  482. .then((response) => {
  483. this.vloading.close();
  484. this.download(response.msg);
  485. })
  486. .catch(() => {
  487. this.vloading.close();
  488. });
  489. },
  490. del(item) {
  491. this.$confirm(`确认删除商品 “${item.title}” 吗?`, '删除商品', {
  492. confirmButtonText: '确定',
  493. cancelButtonText: '取消',
  494. type: 'warning'
  495. }).then(() => {
  496. delGoods(item.goodsId).then(res => {
  497. if (res.code === 0) {
  498. this.$message.success('操作已完成!')
  499. this.getList()
  500. }
  501. })
  502. })
  503. }
  504. }
  505. }
  506. </script>