index.vue 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. <template>
  2. <div id="goods">
  3. <template v-if="view === 'list'">
  4. <data-search :fields="searchFields" v-model="searchInfo" @query="search">
  5. <template #status>
  6. <el-option v-for="i in goodsStatusList" :key="i.value" :label="i.label" :value="i.value"></el-option>
  7. </template>
  8. </data-search>
  9. <data-btn :fields="btnList" @add="toAdd"></data-btn>
  10. <data-table
  11. ref="dataTable"
  12. :fields="fields"
  13. :opera="opera"
  14. :data="list"
  15. :total="total"
  16. :limit="limit"
  17. @query="search"
  18. @edit="toEdit"
  19. @puton="toPuton"
  20. @lower="toLower"
  21. @delete="toDelete"
  22. @spec="toSpec"
  23. @copy="toCopy"
  24. ></data-table>
  25. </template>
  26. <template v-else>
  27. <el-row>
  28. <el-col :span="24">
  29. <el-button type="primary" size="mini" @click="toBack()">返回</el-button>
  30. </el-col>
  31. <el-col :span="24">
  32. <data-form :fields="infoFields" :rules="rules" v-model="form" labelWidth="150px" @save="toSave">
  33. <template #tags="{ item }">
  34. <el-cascader v-model="form[item.model]" :options="tagsList" :props="props" clearable filterable :show-all-levels="false"></el-cascader>
  35. </template>
  36. <template #act_tags>
  37. <el-option v-for="i in act_tagsList" :key="i.value" :label="i.label" :value="i.value"></el-option>
  38. </template>
  39. <template #status>
  40. <el-option v-for="i in goodsStatusList" :key="i.value" :label="i.label" :value="i.value"></el-option>
  41. </template>
  42. <template #brief>
  43. <editor v-model="form.brief" url="/files/point/goods/upload" />
  44. </template>
  45. </data-form>
  46. </el-col>
  47. </el-row>
  48. </template>
  49. </div>
  50. </template>
  51. <script>
  52. const _ = require('lodash');
  53. import methodsUtil from '@/util/opera';
  54. import { mapState, createNamespacedHelpers } from 'vuex';
  55. const { mapActions: goods } = createNamespacedHelpers('goods');
  56. const { mapActions: goodsTags } = createNamespacedHelpers('goodsTags');
  57. const { mapActions: dictData } = createNamespacedHelpers('dictData');
  58. const { mapActions: actTags } = createNamespacedHelpers('actTags');
  59. export default {
  60. name: 'index',
  61. props: {},
  62. components: { editor: () => import('@/components/editor.vue') },
  63. data: function () {
  64. return {
  65. view: 'list',
  66. fields: [
  67. { label: '排序', model: 'sort' },
  68. { label: '商品名称', model: 'name' },
  69. { label: '店铺名称', model: 'shop.name' },
  70. { label: '商品分类', model: 'tags', format: (i) => this.getTags(i) },
  71. { label: '活动标签', model: 'act_tags', format: (i) => this.getAct_tags(i) },
  72. { label: '商品状态', model: 'status', format: (i) => this.getStatus(i) },
  73. ],
  74. opera: [
  75. { label: '修改', method: 'edit' },
  76. { label: '上架', method: 'puton', display: (i) => i.status == '0' },
  77. { label: '下架', method: 'lower', display: (i) => i.status == '1' },
  78. { label: '库存管理', method: 'spec' },
  79. { label: '复制', method: 'copy' },
  80. { label: '删除', method: 'delete', confirm: true, type: 'danger' },
  81. ],
  82. btnList: [{ label: '添加', method: 'add' }],
  83. searchFields: [
  84. { label: '商品名称', model: 'name' },
  85. { label: '商品状态', model: 'status', type: 'select' },
  86. ],
  87. searchInfo: {},
  88. list: [],
  89. total: 0,
  90. limit: 50,
  91. // info部分
  92. infoFields: [
  93. { label: '商品名称', model: 'name' },
  94. { label: '商品分类', model: 'tags', custom: true },
  95. { label: '活动标签', model: 'act_tags', type: 'selectMany' },
  96. { label: '简短简介', model: 'shot_brief', maxLength: 50 },
  97. { label: '预计发货时间', model: 'send_time' },
  98. { label: '商品状态', model: 'status', type: 'select' },
  99. { label: '商品来源', model: 'source' },
  100. { label: '网址', model: 'url' },
  101. { label: '排序', model: 'sort', type: 'number' },
  102. { label: '商品图片', model: 'file', type: 'upload', url: '/files/point/goods/upload' },
  103. { label: '商品介绍', model: 'brief', custom: true },
  104. ],
  105. rules: {},
  106. form: {},
  107. // 商品分类
  108. tagsList: [],
  109. props: { multiple: true, label: 'label', value: 'code' },
  110. // 活动标签
  111. act_tagsList: [],
  112. goodsStatusList: [],
  113. };
  114. },
  115. created() {
  116. this.searchOthers();
  117. this.search();
  118. },
  119. methods: {
  120. ...dictData({ getDict: 'query' }),
  121. ...actTags({ actQuery: 'query' }),
  122. ...goodsTags(['tree']),
  123. ...goods(['copy', 'query', 'delete', 'fetch', 'update', 'create']),
  124. ...methodsUtil,
  125. // 查询
  126. async search({ skip = 0, limit = this.limit, ...others } = {}) {
  127. let query = { skip, limit, ...others, shop: this.user.shop.id };
  128. if (Object.keys(this.searchInfo).length > 0) query = { ...query, ...this.searchInfo };
  129. const res = await this.query(query);
  130. if (this.$checkRes(res)) {
  131. this.$set(this, `list`, res.data);
  132. this.$set(this, `total`, res.total);
  133. }
  134. },
  135. // 添加自定义
  136. initAddData() {
  137. const obj = {
  138. status: '1',
  139. shop: _.get(this.shop, '_id'),
  140. };
  141. this.$set(this, 'form', obj);
  142. },
  143. // 复制
  144. async toCopy({ data }) {
  145. this.$confirm('是否确认复制该商品?', '提示', {
  146. confirmButtonText: '确定',
  147. cancelButtonText: '取消',
  148. type: 'warning',
  149. }).then(async () => {
  150. let res;
  151. res = await this.copy(data.id);
  152. if (this.$checkRes(res)) {
  153. this.$message({ type: `success`, message: `复制成功` });
  154. this.toBack();
  155. this.search();
  156. }
  157. });
  158. },
  159. // 查询其他信息
  160. async searchOthers() {
  161. let res = await this.tree();
  162. if (this.$checkRes(res)) this.$set(this, `tagsList`, res.data);
  163. res = await this.getDict({ code: 'goods_status' });
  164. if (this.$checkRes(res)) this.$set(this, `goodsStatusList`, res.data);
  165. res = await this.actQuery();
  166. if (this.$checkRes(res)) this.$set(this, `act_tagsList`, res.data);
  167. },
  168. // 商品状态
  169. getStatus(data) {
  170. const res = this.goodsStatusList.find((f) => f.value === data);
  171. if (res) return res.label;
  172. return '';
  173. },
  174. // 活动标签
  175. getAct_tags(data) {
  176. const arr = [];
  177. for (const val of data) {
  178. const r = this.act_tagsList.find((f) => f.value === val);
  179. if (r) arr.push(r.label);
  180. }
  181. return arr.join(';');
  182. },
  183. // 商品分类
  184. getTags(data) {
  185. let list = this.tagsList;
  186. const getChildren = (list) =>
  187. list.map((i) => {
  188. if (i.children) return getChildren(i.children);
  189. return i;
  190. });
  191. list = _.flattenDeep(getChildren(list));
  192. const arr = [];
  193. for (const ts of data) {
  194. const last = _.last(ts);
  195. const r = list.find((f) => f.code === last);
  196. if (r) arr.push(r.label);
  197. }
  198. return arr.join(';');
  199. },
  200. // 保存
  201. async toSave({ data }) {
  202. data.shop = this.user.shop.id;
  203. let res;
  204. if (data.id) res = await this.update(data);
  205. else res = await this.create(data);
  206. if (this.$checkRes(res)) {
  207. this.$message({ type: `success`, message: `维护信息成功` });
  208. this.toBack();
  209. this.search();
  210. }
  211. },
  212. // 执行返回
  213. toBack() {
  214. this.form = {};
  215. this.view = 'list';
  216. },
  217. // 上架
  218. async toPuton({ data }) {
  219. this.$confirm('是否确认上架该商品?', '提示', {
  220. confirmButtonText: '确定',
  221. cancelButtonText: '取消',
  222. type: 'warning',
  223. }).then(async () => {
  224. data.status = '1';
  225. let res;
  226. if (data.id) res = await this.update(data);
  227. if (this.$checkRes(res)) {
  228. this.$message({ type: `success`, message: `上架成功` });
  229. }
  230. this.search();
  231. });
  232. },
  233. // 下架
  234. async toLower({ data }) {
  235. this.$confirm('是否确认下架该商品?', '提示', {
  236. confirmButtonText: '确定',
  237. cancelButtonText: '取消',
  238. type: 'warning',
  239. }).then(async () => {
  240. data.status = '0';
  241. let res;
  242. if (data._id) res = await this.update(data);
  243. if (this.$checkRes(res)) {
  244. this.$message({ type: `success`, message: `下架成功` });
  245. }
  246. this.search();
  247. });
  248. },
  249. // 库存管理
  250. toSpec({ data }) {
  251. this.$router.push({ path: `/selfShop/spec/${data._id}` });
  252. },
  253. },
  254. computed: {
  255. ...mapState(['user']),
  256. },
  257. };
  258. </script>
  259. <style lang="less" scoped></style>