YY 2 anni fa
parent
commit
7033e96913

+ 6 - 0
src/router/module/platActivi.js

@@ -54,4 +54,10 @@ export default [
     meta: { title: '平台管理-平台活动商品规格添加' },
     component: () => import('@/views/platActivi/act/parts/goods/goodsSpec.vue'),
   },
+  {
+    path: '/platActivi/goodsSet',
+    name: 'platActivi_goodsSet',
+    meta: { title: '平台管理-套装管理' },
+    component: () => import('@/views/platActivi/goodsSet/index.vue'),
+  },
 ];

+ 3 - 0
src/store/index.js

@@ -30,6 +30,8 @@ import indexModule from './module/system/indexModule';
 import actTags from './module/system/actTags';
 import config from './module/system/config';
 import platformAct from './module/system/platformAct';
+// 套装
+import goodsSet from './module/system/goodsSet';
 import goodsJoinAct from './module/system/goodsJoinAct';
 import admins from './module/system/admin';
 
@@ -121,5 +123,6 @@ export default new Vuex.Store({
     shopCashOut,
     getBill,
     shopNotice,
+    goodsSet,
   },
 });

+ 44 - 0
src/store/module/system/goodsSet.js

@@ -0,0 +1,44 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+const _ = require('lodash');
+Vue.use(Vuex);
+const api = {
+  url: '/point/v1/api/goodsSet',
+};
+
+const state = () => ({});
+const mutations = {};
+
+const actions = {
+  async query({ commit }, { skip = 0, limit, ...info } = {}) {
+    const res = await this.$axios.$get(`${api.url}`, {
+      skip,
+      limit,
+      ...info,
+    });
+    return res;
+  },
+  async create({ commit }, payload) {
+    const res = await this.$axios.$post(`${api.url}`, payload);
+    return res;
+  },
+  async fetch({ commit }, payload) {
+    const res = await this.$axios.$get(`${api.url}/${payload}`);
+    return res;
+  },
+  async update({ commit }, payload) {
+    const id = _.get(payload, 'id', _.get(payload, '_id'));
+    const res = await this.$axios.$post(`${api.url}/${id}`, payload);
+    return res;
+  },
+  async delete({ commit }, payload) {
+    const res = await this.$axios.$delete(`${api.url}/${payload}`);
+    return res;
+  },
+};
+export default {
+  namespaced: true,
+  state,
+  mutations,
+  actions,
+};

+ 298 - 0
src/views/platActivi/goodsSet/detail.vue

@@ -0,0 +1,298 @@
+<template>
+  <div id="detail">
+    <el-row>
+      <el-col :span="24" class="main" v-loading="loadings" element-loading-text="拼命加载中" element-loading-spinner="el-icon-loading">
+        <el-col :span="24" style="margin: 0 0 10px 0">
+          <el-col :span="2"><el-button type="primary" size="mini" @click="toBack()">返回</el-button></el-col>
+        </el-col>
+        <el-col :span="24">
+          <data-form :fields="infoFields" :rules="rules" v-model="form" labelWidth="150px" @save="toSave" @dataChange="dataChange">
+            <template #is_use>
+              <el-option v-for="i in is_useList" :key="i.model" :label="i.label" :value="i.value"></el-option>
+            </template>
+            <template #single_stock>
+              <el-select v-model="form.single_stock" placeholder="请选择" style="width: 100%">
+                <el-option v-for="i in is_useList" :key="i.model" :label="i.label" :value="i.value"></el-option>
+              </el-select>
+              <p style="margin: 5px 0 0 0; font-size: 12px">禁用状态不需要填写库存数量,直接使用商品规格库存</p>
+            </template>
+            <template #set>
+              <el-col :span="24" style="margin: 0 0 10px 0">
+                <el-button type="primary" size="mini" @click="toAdd()">添加规格商品</el-button>
+              </el-col>
+              <el-table :data="form.set" border size="mini">
+                <el-table-column label="店铺名称" prop="shop_name" align="center">
+                  <template #default="{ row }">
+                    <p>{{ row.shop_name }}</p>
+                  </template>
+                </el-table-column>
+                <el-table-column label="商品名称" prop="goods_name" align="center">
+                  <template #default="{ row }">
+                    <p>{{ row.goods_name }}</p>
+                  </template>
+                </el-table-column>
+                <el-table-column label="规格名称" prop="spec_name" align="center">
+                  <template #default="{ row }">
+                    <p>{{ row.spec_name }}</p>
+                  </template>
+                </el-table-column>
+                <el-table-column label="组合套装数量" prop="set_num" align="center">
+                  <template #default="{ row }">
+                    <el-input v-model="row.set_num" type="number" placeholder="请输入组合套装数量"></el-input>
+                  </template>
+                </el-table-column>
+                <el-table-column label="套装销售金额" prop="set_money" align="center">
+                  <template #default="{ row }">
+                    <el-input v-model="row.set_money" type="number" placeholder="请输入套装销售金额"></el-input>
+                  </template>
+                </el-table-column>
+                <el-table-column label="操作" align="center">
+                  <template #default="scope">
+                    <el-button type="danger" size="mini" @click="toDel(scope.$index, 'set')">删除</el-button>
+                  </template>
+                </el-table-column>
+              </el-table>
+              <el-col :span="24" style="margin: 10px 0 0 0; text-align: center">
+                <el-button type="warning" size="mini" @click="toMoney()">计算套装金额</el-button>
+              </el-col>
+            </template>
+            <template #stock v-if="form.single_stock == '0'">
+              <el-input v-model="form.stock" type="number" placeholder="请输入库存数量"></el-input>
+            </template>
+          </data-form>
+        </el-col>
+      </el-col>
+    </el-row>
+    <e-dialog :dialog="dialog" @toClose="toClose">
+      <template v-slot:info>
+        <data-form :fields="diaFields" :rules="diaRules" v-model="diaForm" labelWidth="150px" @save="onSubmit" @dataChange="diaChange">
+          <template #shop>
+            <el-select
+              v-model="diaForm.shop"
+              filterable
+              clearable
+              remote
+              reserve-keyword
+              :remote-method="shopSearch"
+              placeholder="请输入店铺名称,便于查询商品"
+              :loading="loading"
+              @change="shopSelect"
+              style="width: 100%"
+            >
+              <el-option v-for="item in shopList" :key="item._id" :label="item.name" :value="item._id"> </el-option>
+            </el-select>
+          </template>
+          <template #goods>
+            <el-option v-for="item in goodsList" :key="item._id" :label="item.name" :value="item._id"> </el-option>
+          </template>
+          <template #spec>
+            <el-option v-for="item in specList" :key="item._id" :label="item.name" :value="item._id"> </el-option>
+          </template>
+        </data-form>
+      </template>
+    </e-dialog>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+import * as util from '@/util/computed';
+const _ = require('lodash');
+const { mapActions: goodsSet } = createNamespacedHelpers('goodsSet');
+const { mapActions: goods } = createNamespacedHelpers('goods');
+const { mapActions: shop } = createNamespacedHelpers('shop');
+const { mapActions: goodsSpec } = createNamespacedHelpers('goodsSpec');
+const { mapActions: dictData } = createNamespacedHelpers('dictData');
+
+export default {
+  name: 'detail',
+  props: { id: { type: String } },
+  components: {},
+  data: function () {
+    return {
+      loadings: true,
+      // form
+      infoFields: [
+        { label: '套装名称', model: 'name' },
+        { label: '是否使用', model: 'is_use', type: 'select' },
+        { label: '商品规格组合', model: 'set', custom: true },
+        { label: '套装销售金额', model: 'sell_money', type: 'number' },
+        { label: '运费', model: 'freight', type: 'number' },
+        { label: '单独设置库存', model: 'single_stock', custom: true },
+        { label: '库存数量', model: 'stock', custom: true },
+      ],
+      rules: {
+        name: [{ required: true, message: '套装名称', trigger: 'blur' }],
+        is_use: [{ required: true, message: '是否使用', trigger: 'change' }],
+        sell_money: [{ required: true, message: '套装销售金额', trigger: 'blur' }],
+        freight: [{ required: true, message: '运费', trigger: 'blur' }],
+      },
+      form: {
+        set: [],
+      },
+      // 是否使用
+      is_useList: [],
+      // 弹框
+      dialog: { title: '信息管理', show: false, type: '1' },
+      diaFields: [
+        { label: '店铺名称', model: 'shop', custom: true },
+        { label: '商品名称', model: 'goods', type: 'select' },
+        { label: '规格名称', model: 'spec', type: 'select' },
+        { label: '数量', model: 'set_num', type: 'number' },
+        { label: '单价', model: 'set_money', type: 'number' },
+      ],
+      diaRules: {
+        // shop: [{ required: true, message: '店铺名称', trigger: 'change' }],
+        goods: [{ required: true, message: '商品名称', trigger: 'change' }],
+        spec: [{ required: true, message: '规格名称', trigger: 'blur' }],
+        set_num: [{ required: true, message: '数量', trigger: 'blur' }],
+        set_money: [{ required: true, message: '单价', trigger: 'blur' }],
+      },
+      diaForm: {},
+      list: [],
+      loading: false,
+      shopList: [],
+      goodsList: [],
+      specList: [],
+    };
+  },
+  created() {
+    this.searchOthers();
+    this.search();
+  },
+  methods: {
+    ...dictData({ getDict: 'query' }),
+    ...shop({ shopQuery: 'query', shopFetch: 'fetch' }),
+    ...goods({ goodsQuery: 'query', goodsFetch: 'fetch' }),
+    ...goodsSpec({ specQuery: 'query', specFetch: 'fetch' }),
+    ...goodsSet(['query', 'delete', 'fetch', 'update', 'create']),
+
+    // 查询
+    async search() {
+      if (this.id) {
+        const res = await this.fetch(this.id);
+        if (this.$checkRes(res)) this.$set(this, `form`, res.data);
+      } else {
+        const obj = { is_use: '0', single_stock: '1', set: [], freight: 0 };
+        this.$set(this, 'form', obj);
+      }
+      this.loadings = false;
+    },
+    toAdd() {
+      this.dialog = { title: '信息管理', show: true, type: '1' };
+    },
+    // 远程查询店铺
+    async shopSearch(value) {
+      this.loading = true;
+      let res = await this.shopQuery({ name: value });
+      if (this.$checkRes(res)) this.$set(this, 'shopList', res.data);
+      this.loading = false;
+    },
+    // 选择-查询商品
+    async shopSelect(value) {
+      let res = await this.goodsQuery({ shop: value });
+      if (this.$checkRes(res)) this.$set(this, 'goodsList', res.data);
+      res = await this.shopFetch(value);
+      if (this.$checkRes(res)) this.$set(this.diaForm, 'shop_name', res.data.name);
+    },
+    async diaChange({ model, value }) {
+      if (model == 'goods') {
+        let res = await this.specQuery({ goods: value });
+        if (this.$checkRes(res)) this.$set(this, 'specList', res.data);
+        res = await this.goodsFetch(value);
+        if (this.$checkRes(res)) this.$set(this.diaForm, 'goods_name', res.data.name);
+      } else if (model == 'spec') {
+        let res = await this.specFetch(value);
+        if (this.$checkRes(res)) {
+          this.$set(this.diaForm, 'spec_name', res.data.name);
+          this.$set(this.diaForm, 'set_money', res.data.sell_money);
+        }
+      }
+    },
+    onSubmit({ data }) {
+      if (this.form.set.length == 0) {
+        let list = [];
+        list.push(data);
+        this.$set(this.form, 'set', list);
+      } else {
+        this.form.set.push(data);
+      }
+      this.toClose();
+    },
+    // 关闭
+    toClose() {
+      this.diaForm = {};
+      this.dialog = { title: '信息管理', show: false, type: '1' };
+    },
+    // 删除
+    toDel(index, type) {
+      var list = this.form.set;
+      list.splice(index, 1);
+    },
+    // 计算金额
+    toMoney() {
+      let money = 0;
+      for (const p1 of this.form.set) {
+        money += util.multiply(p1.set_num, p1.set_money);
+      }
+      this.$set(this.form, 'sell_money', money);
+    },
+    dataChange({ model, value }) {},
+
+    // 保存
+    async toSave({ data }) {
+      if (data.set.length > 0) {
+        let shop = [];
+        let goods = [];
+        let spec = [];
+        for (const p1 of data.set) {
+          shop.push(p1.shop);
+          goods.push(p1.goods);
+          spec.push(p1.spec);
+        }
+        data.shop = _.uniq(shop);
+        data.goods = _.uniq(goods);
+        data.spec = _.uniq(spec);
+        this.toRef(data);
+      } else {
+        this.$message({ type: `warning`, message: `还未添加套装商品,不可保存` });
+      }
+    },
+    async toRef(data) {
+      console.log(data);
+      let res;
+      if (data._id) res = await this.update(data);
+      else res = await this.create(data);
+      if (this.$checkRes(res)) {
+        this.$message({ type: `success`, message: `维护信息成功` });
+        this.toBack();
+      }
+    },
+    // 返回
+    toBack() {
+      this.$emit('toBack');
+    },
+    // 查询其他信息
+    async searchOthers() {
+      // 是否使用
+      let res = await this.getDict({ code: 'use' });
+      if (this.$checkRes(res)) this.$set(this, 'is_useList', res.data);
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 230 - 0
src/views/platActivi/goodsSet/index.vue

@@ -0,0 +1,230 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col
+        :span="24"
+        class="main animate__animated animate__backInRight"
+        v-loading="loadings"
+        element-loading-text="拼命加载中"
+        element-loading-spinner="el-icon-loading"
+      >
+        <span v-show="view === 'list'">
+          <el-col :span="24" class="one"> <span>套装管理</span> </el-col>
+          <el-col :span="24" class="two">
+            <search-1 :form="searchForm" @onSubmit="toSearch" @toReset="toClose"></search-1>
+          </el-col>
+          <el-col :span="24" class="thr">
+            <el-button type="primary" size="mini" @click="toAdd()">新增</el-button>
+          </el-col>
+          <el-col :span="24" class="four">
+            <data-table
+              ref="dataTable"
+              :fields="fields"
+              :opera="opera"
+              @query="search"
+              :data="list"
+              :total="total"
+              @edit="toEdit"
+              @del="toDel"
+              @manage="toManage"
+            >
+            </data-table>
+          </el-col>
+        </span>
+        <detail v-if="view === 'info'" :id="id" @toBack="toBack"></detail>
+      </el-col>
+    </el-row>
+    <e-dialog :dialog="dialog" @toClose="toClose">
+      <template v-slot:info>
+        <el-table :data="set" border size="mini">
+          <el-table-column label="店铺名称" prop="shop_name" align="center">
+            <template #default="{ row }">
+              <p>{{ row.shop_name }}</p>
+            </template>
+          </el-table-column>
+          <el-table-column label="商品名称" prop="goods_name" align="center">
+            <template #default="{ row }">
+              <p>{{ row.goods_name }}</p>
+            </template>
+          </el-table-column>
+          <el-table-column label="规格名称" prop="spec_name" align="center">
+            <template #default="{ row }">
+              <p>{{ row.spec_name }}</p>
+            </template>
+          </el-table-column>
+          <el-table-column label="组合套装数量" prop="set_num" align="center">
+            <template #default="{ row }">
+              <p>{{ row.set_num }}</p>
+            </template>
+          </el-table-column>
+          <el-table-column label="套装销售金额" prop="set_money" align="center">
+            <template #default="{ row }">
+              <p>{{ row.set_money }}</p>
+            </template>
+          </el-table-column>
+        </el-table>
+      </template>
+    </e-dialog>
+  </div>
+</template>
+
+<script>
+const _ = require('lodash');
+import { mapState, mapGetters, createNamespacedHelpers } from 'vuex';
+const { mapActions } = createNamespacedHelpers('goodsSet');
+const { mapActions: dictData } = createNamespacedHelpers('dictData');
+export default {
+  name: 'index',
+  props: {},
+  components: {
+    search1: () => import('./parts/search-1.vue'),
+    detail: () => import('./detail.vue'),
+  },
+  data: function () {
+    const that = this;
+    return {
+      loadings: true,
+      view: 'list',
+      // 列表
+      opera: [
+        { label: '修改', method: 'edit' },
+        { label: '商品管理', method: 'manage' },
+        { label: '删除', method: 'del', confirm: true, type: 'danger' },
+      ],
+      fields: [
+        { label: '套装名称', model: 'name' },
+        // { label: '店铺名称', model: 'shop', format: (i) => i.join(',') },
+        // { label: '商品', model: 'goods', format: (i) => i.join(',') },
+        // { label: '规格', model: 'spec', format: (i) => i.join(',') },
+        { label: '套装销售金额', model: 'sell_money' },
+        { label: '运费', model: 'freight' },
+        {
+          label: '是否开启',
+          model: 'is_use',
+          format: (i) => {
+            let data = that.isuseList.find((f) => f.value == i);
+            if (data) return data.label;
+            else return '暂无';
+          },
+        },
+      ],
+      list: [],
+      total: 0,
+      // 查询
+      searchForm: {},
+      // 是否开启
+      isuseList: [],
+      id: '',
+      // 查询条件
+      searchQuery: {},
+      set: [],
+      // 弹框
+      dialog: { title: '信息管理', show: false, type: '1' },
+    };
+  },
+  created() {
+    this.searchOther();
+    this.search();
+  },
+  methods: {
+    ...dictData({ dictQuery: 'query' }),
+    ...mapActions(['query', 'fetch', 'create', 'update', 'delete']),
+    toSearch() {
+      this.$refs.dataTable.resetPage();
+      let res = this.$refs.dataTable.getPageConfig();
+      this.search(res);
+    },
+    // 查询
+    async search({ skip = 0, limit = this.$limit, ...others } = {}) {
+      const condition = _.cloneDeep(this.searchForm);
+      let query = { skip, limit, ...others };
+      if (Object.keys(condition).length > 0) query = { ...query, ...condition };
+      let res = await this.query(query);
+      if (this.$checkRes(res)) {
+        this.$set(this, 'list', res.data);
+        this.$set(this, 'total', res.total);
+        this.$set(this, `searchQuery`, query);
+      }
+      this.loadings = false;
+    },
+    // 新增
+    toAdd() {
+      let id = '';
+      this.$set(this, `id`, id);
+      this.$set(this, `view`, 'info');
+    },
+    // 修改
+    async toEdit({ data }) {
+      this.$set(this, `id`, data.id);
+      this.$set(this, `view`, 'info');
+    },
+    toBack() {
+      this.view = 'list';
+      this.search(this.searchQuery);
+    },
+    // 商品管理
+    async toManage({ data }) {
+      this.$set(this, `set`, data.set);
+      this.dialog = { title: '信息管理', show: true, type: '1' };
+    },
+    // 关闭
+    toClose() {
+      this.set = [];
+      this.searchForm = {};
+      this.dialog = { title: '信息管理', show: false, type: '1' };
+      this.search();
+    },
+    // 删除
+    async toDel({ data }) {
+      let res = await this.delete(data._id);
+      if (this.$checkRes(res)) {
+        this.$message({ type: `success`, message: `刪除信息成功` });
+        this.search(this.searchQuery);
+      }
+    },
+    // 查询其他信息
+    async searchOther() {
+      let res;
+      // 是否使用
+      res = await this.dictQuery({ code: 'use' });
+      if (this.$checkRes(res)) this.$set(this, `isuseList`, res.data);
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  .one {
+    margin: 0 0 10px 0;
+
+    span:nth-child(1) {
+      font-size: 20px;
+      font-weight: 700;
+      margin-right: 10px;
+    }
+  }
+  .two {
+    margin: 0 0 10px 0;
+  }
+  .thr {
+    margin: 0 0 10px 0;
+  }
+}
+.el-col {
+  margin: 10px 0;
+}
+</style>

+ 96 - 0
src/views/platActivi/goodsSet/parts/search-1.vue

@@ -0,0 +1,96 @@
+<template>
+  <div id="search-1">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-form :model="form" ref="form" label-width="130px">
+          <!-- <el-col :span="6">
+            <el-form-item label="店铺名称" prop="type">
+              <el-select
+                v-model="form.shop"
+                filterable
+                remote
+                reserve-keyword
+                placeholder="请输入商铺名称"
+                :remote-method="querySearch"
+                :loading="loading"
+                @change="handleSelect"
+              >
+                <el-option v-for="item in shopList" :key="item.id" :label="item.name" :value="item.id"> </el-option>
+              </el-select>
+            </el-form-item>
+          </el-col> -->
+          <el-col :span="6">
+            <el-form-item label="套装名称" prop="name">
+              <el-input v-model="form.name" placeholder="请输入优惠券名称" size="small"></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col :span="24" class="btn">
+            <el-button type="primary" icon="el-icon-search" size="mini" @click="onSubmit('form')">搜索</el-button>
+            <el-button icon="el-icon-refresh" size="mini" @click="toReset('form')">重置</el-button>
+          </el-col>
+        </el-form>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'search-1',
+  props: {
+    form: { type: Object },
+    statusList: { type: Array },
+    shopList: { type: Array },
+    discount_typeList: { type: Array },
+  },
+  components: {},
+  data: function () {
+    return {
+      loading: false,
+    };
+  },
+  created() {},
+  methods: {
+    querySearch(value) {
+      this.loading = true;
+      this.$emit('querySearch', value);
+      this.loading = false;
+    },
+    handleSelect(value) {
+      this.$set(this.form, `shop`, value);
+    },
+    onSubmit() {
+      this.$emit('onSubmit');
+    },
+    toReset(formName) {
+      this.$refs[formName].resetFields();
+      this.$emit('toReset');
+    },
+  },
+  computed: {},
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  .btn {
+    text-align: right;
+  }
+  /deep/.el-form-item {
+    float: left;
+    width: 100%;
+    margin: 0 0 10px 0;
+  }
+}
+</style>