index.vue 10 KB

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