Browse Source

修改菜单

YY 2 years ago
parent
commit
be207bc5bf
48 changed files with 5752 additions and 42 deletions
  1. 1 1
      src/layout/Sidebar.vue
  2. 69 40
      src/layout/data/menu.js
  3. 2 0
      src/router/index.js
  4. 51 0
      src/router/module/platActivi.js
  5. 38 0
      src/router/module/platSettings.js
  6. 14 0
      src/router/module/platfinance.js
  7. 38 0
      src/router/module/platmanag.js
  8. 151 0
      src/views/platActivi/act/detail.vue
  9. 130 0
      src/views/platActivi/act/goods.vue
  10. 157 0
      src/views/platActivi/act/goodsDetail.vue
  11. 163 0
      src/views/platActivi/act/index.vue
  12. 70 0
      src/views/platActivi/act/parts/search-1.vue
  13. 119 0
      src/views/platActivi/actTags/detail.vue
  14. 168 0
      src/views/platActivi/actTags/index.vue
  15. 70 0
      src/views/platActivi/actTags/parts/search-1.vue
  16. 331 0
      src/views/platActivi/coupon/detail.vue
  17. 208 0
      src/views/platActivi/coupon/index.vue
  18. 111 0
      src/views/platActivi/coupon/parts/search-1.vue
  19. 137 0
      src/views/platSettings/banner/detail.vue
  20. 175 0
      src/views/platSettings/banner/index.vue
  21. 72 0
      src/views/platSettings/banner/parts/search-1.vue
  22. 64 0
      src/views/platSettings/config/index.vue
  23. 123 0
      src/views/platSettings/indexModule/detail.vue
  24. 172 0
      src/views/platSettings/indexModule/index.vue
  25. 73 0
      src/views/platSettings/indexModule/parts/search-1.vue
  26. 82 0
      src/views/platSettings/service/index.vue
  27. 200 0
      src/views/platfinance/bill/index.vue
  28. 97 0
      src/views/platfinance/bill/parts/search-1.vue
  29. 87 0
      src/views/platfinance/statistics/index.vue
  30. 142 0
      src/views/platfinance/statistics/parts/card-1.vue
  31. 143 0
      src/views/platfinance/statistics/parts/card-2.vue
  32. 145 0
      src/views/platfinance/statistics/parts/card-3.vue
  33. 145 0
      src/views/platfinance/statistics/parts/card-4.vue
  34. 145 0
      src/views/platfinance/statistics/parts/card-5.vue
  35. 147 0
      src/views/platfinance/statistics/parts/card-6.vue
  36. 187 0
      src/views/platmanag/goodsRate/detail.vue
  37. 123 0
      src/views/platmanag/goodsRate/index.vue
  38. 65 0
      src/views/platmanag/goodsRate/parts/search-1.vue
  39. 156 0
      src/views/platmanag/goodsTags/index.vue
  40. 177 0
      src/views/platmanag/order/detail_order.vue
  41. 341 0
      src/views/platmanag/order/detail_orderDetail.vue
  42. 104 0
      src/views/platmanag/order/index.vue
  43. 116 0
      src/views/platmanag/order/parts/card-1.vue
  44. 112 0
      src/views/platmanag/order/parts/card-2.vue
  45. 113 0
      src/views/platmanag/order/parts/card-3.vue
  46. 113 0
      src/views/platmanag/order/parts/card-4.vue
  47. 104 0
      src/views/platmanag/order/parts/search-1.vue
  48. 1 1
      src/views/selfShop/goods/spec.vue

+ 1 - 1
src/layout/Sidebar.vue

@@ -55,7 +55,7 @@
 </template>
 
 <script>
-const { system, adminMenu, devMenu } = require('./data/menu');
+const { system, platActiviMenu, adminMenu, devMenu } = require('./data/menu');
 const { menuInfo } = require('./data/site');
 import { mapState, createNamespacedHelpers } from 'vuex';
 import _ from 'lodash';

+ 69 - 40
src/layout/data/menu.js

@@ -16,119 +16,148 @@ export const adminMenu = [
     children: [
       {
         icon: 'icon-rencai',
-        path: '/system/config',
-        name: '系统设置',
+        path: '/platmanag/goodsTags',
+        name: '商品标签',
         index: '2-1',
       },
       {
         icon: 'icon-rencai',
-        path: '/system/indexModule',
-        name: '首页图标设置',
+        path: '/platmanag/order',
+        name: '平台订单管理',
         index: '2-2',
       },
       {
         icon: 'icon-rencai',
-        path: '/system/banner',
-        name: '广告图',
+        path: '/platmanag/goodsRate',
+        name: '商品评价',
         index: '2-3',
       },
+    ],
+  },
+  {
+    icon: 'icon-shouye',
+    // path: '/',
+    name: '平台活动',
+    index: '3',
+    type: '0',
+    children: [
       {
         icon: 'icon-rencai',
-        path: '/system/goodsTags',
-        name: '商品标签',
-        index: '2-4',
+        path: '/platActivi/actTags',
+        name: '活动标签',
+        index: '3-1',
       },
       {
         icon: 'icon-rencai',
-        path: '/system/actTags',
-        name: '活动标签',
-        index: '2-5',
+        path: '/platActivi/coupon',
+        name: '优惠券管理',
+        index: '3-2',
       },
       {
         icon: 'icon-rencai',
-        path: '/system/order',
-        name: '平台订单管理',
-        index: '2-6',
+        path: '/platActivi/act',
+        name: '平台活动',
+        index: '3-3',
       },
+    ],
+  },
+  {
+    icon: 'icon-shouye',
+    // path: '/',
+    name: '平台财务',
+    index: '4',
+    type: '0',
+    children: [
       {
         icon: 'icon-rencai',
-        path: '/system/coupon',
-        name: '优惠券管理',
-        index: '2-7',
+        path: '/platfinance/statistics',
+        name: '统计',
+        index: '4-1',
       },
+
       {
         icon: 'icon-rencai',
-        path: '/system/service',
-        name: '客服管理',
-        index: '2-8',
+        path: '/platfinance/bill',
+        name: '账单管理',
+        index: '4-2',
       },
+    ],
+  },
+  {
+    icon: 'icon-shouye',
+    // path: '/',
+    name: '平台设置',
+    index: '5',
+    type: '0',
+    children: [
       {
         icon: 'icon-rencai',
-        path: '/system/statistics',
-        name: '统计',
-        index: '2-9',
+        path: '/platSettings/config',
+        name: '系统设置',
+        index: '5-1',
       },
       {
         icon: 'icon-rencai',
-        path: '/system/goodsRate',
-        name: '商品评价',
-        index: '2-10',
+        path: '/platSettings/indexModule',
+        name: '首页图标设置',
+        index: '5-2',
       },
       {
         icon: 'icon-rencai',
-        path: '/system/act',
-        name: '平台活动',
-        index: '2-11',
+        path: '/platSettings/banner',
+        name: '广告图',
+        index: '5-3',
       },
+
       {
         icon: 'icon-rencai',
-        path: '/system/bill',
-        name: '账单管理',
-        index: '2-12',
+        path: '/platSettings/service',
+        name: '客服管理',
+        index: '5-4',
       },
     ],
   },
   {
     icon: 'icon-shouye',
     name: '自营店铺',
-    index: '3',
+    index: '6',
     type: '0',
     children: [
       {
         icon: 'icon-rencai',
         path: '/selfShop/info',
         name: '店铺信息',
-        index: '3-1',
+        index: '6-1',
       },
       {
         icon: 'icon-rencai',
         path: '/selfShop/goods',
         name: '商品管理',
-        index: '3-2',
+        index: '6-2',
       },
       {
         icon: 'icon-rencai',
         path: '/selfShop/order',
         name: '订单管理',
-        index: '3-3',
+        index: '6-3',
       },
       {
         icon: 'icon-rencai',
         path: '/selfShop/goodsRate',
         name: '商品评价',
-        index: '3-4',
+        index: '6-4',
       },
       {
         icon: 'icon-rencai',
         path: '/selfShop/sales',
         name: '售后管理',
-        index: '3-5',
+        index: '6-5',
       },
       {
         icon: 'icon-rencai',
         path: '/selfShop/bill',
         name: '账单管理',
-        index: '3-6',
+        index: '6-6',
       },
     ],
   },

+ 2 - 0
src/router/index.js

@@ -3,6 +3,7 @@ import VueRouter from 'vue-router';
 import gurad from './guard';
 import selfShop from './module/selfShop';
 import system from './module/system';
+import platActivi from './module/platActivi';
 import dev from './module/dev';
 Vue.use(VueRouter);
 
@@ -29,6 +30,7 @@ const routes = [
       ...dev,
       ...system,
       ...selfShop,
+      ...platActivi,
     ],
   },
 ];

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

@@ -0,0 +1,51 @@
+export default [
+  {
+    path: '/platActivi/coupon',
+    name: 'platActivi_coupon',
+    meta: { title: '平台管理-优惠券管理' },
+    component: () => import(/* webpackChunkName: "platActivi_goodsTags" */ '@/views/platActivi/coupon/index.vue'),
+  },
+  {
+    path: '/platActivi/coupon/detail',
+    name: 'platActivi_coupon_detail',
+    meta: { title: '平台管理-优惠券管理-维护信息' },
+    component: () => import(/* webpackChunkName: "platActivi_coupon_detail" */ '@/views/platActivi/coupon/detail.vue'),
+  },
+
+  {
+    path: '/platActivi/actTags',
+    name: 'platActivi_actTags',
+    meta: { title: '平台管理-活动标签' },
+    component: () => import(/* webpackChunkName: "platActivi_actTags" */ '@/views/platActivi/actTags/index.vue'),
+  },
+  {
+    path: '/platActivi/actTags/detail',
+    name: 'platActivi_actTags_detail',
+    meta: { title: '平台管理-活动标签-维护信息' },
+    component: () => import(/* webpackChunkName: "platActivi_actTags_detail" */ '@/views/platActivi/actTags/detail.vue'),
+  },
+  {
+    path: '/platActivi/act',
+    name: 'platActivi_act',
+    meta: { title: '平台管理-平台活动' },
+    component: () => import(/* webpackChunkName: "platActivi_act" */ '@/views/platActivi/act/index.vue'),
+  },
+  {
+    path: '/platActivi/act/detail',
+    name: 'platActivi_act_detail',
+    meta: { title: '平台管理-平台活动详情' },
+    component: () => import(/* webpackChunkName: "platActivi_act_detail" */ '@/views/platActivi/act/detail.vue'),
+  },
+  {
+    path: '/platActivi/act/goods',
+    name: 'platActivi_act_goods',
+    meta: { title: '平台管理-平台活动商品' },
+    component: () => import(/* webpackChunkName: "platActivi_act_goods" */ '@/views/platActivi/act/goods.vue'),
+  },
+  {
+    path: '/platActivi/act/goodsDetail',
+    name: 'platActivi_act_goodsDetail',
+    meta: { title: '平台管理-平台活动商品添加' },
+    component: () => import(/* webpackChunkName: "platActivi_act_goodsDetail" */ '@/views/platActivi/act/goodsDetail.vue'),
+  },
+];

+ 38 - 0
src/router/module/platSettings.js

@@ -0,0 +1,38 @@
+export default [
+  {
+    path: '/platSettings/banner',
+    name: 'platSettings_banner',
+    meta: { title: '平台管理-广告图' },
+    component: () => import(/* webpackChunkName: "platSettings_banner" */ '@/views/platSettings/banner/index.vue'),
+  },
+  {
+    path: '/platSettings/banner/detail',
+    name: 'platSettings_banner_detail',
+    meta: { title: '平台管理-广告图-维护信息' },
+    component: () => import(/* webpackChunkName: "platSettings_banner_detail" */ '@/views/platSettings/banner/detail.vue'),
+  },
+  {
+    path: '/platSettings/indexModule',
+    name: 'platSettings_indexModule',
+    meta: { title: '平台管理-首页图标设置' },
+    component: () => import(/* webpackChunkName: "platSettings_indexModule" */ '@/views/platSettings/indexModule/index.vue'),
+  },
+  {
+    path: '/platSettings/indexModule/detail',
+    name: 'platSettings_indexModule_detail',
+    meta: { title: '平台管理-首页图标设置-维护信息' },
+    component: () => import(/* webpackChunkName: "platSettings_indexModule_detail" */ '@/views/platSettings/indexModule/detail.vue'),
+  },
+  {
+    path: '/platSettings/service',
+    name: 'platSettings_service',
+    meta: { title: '平台管理-客服管理' },
+    component: () => import(/* webpackChunkName: "platSettings_service" */ '@/views/platSettings/service/index.vue'),
+  },
+  {
+    path: '/platSettings/config',
+    name: 'platSettings_config',
+    meta: { title: '平台管理-系统设置' },
+    component: () => import(/* webpackChunkName: "platSettings_config" */ '@/views/platSettings/config/index.vue'),
+  },
+];

+ 14 - 0
src/router/module/platfinance.js

@@ -0,0 +1,14 @@
+export default [
+  {
+    path: '/platfinance/statistics',
+    name: 'platfinance_statistics',
+    meta: { title: '平台管理-统计' },
+    component: () => import(/* webpackChunkName: "platfinance_statistics" */ '@/views/platfinance/statistics/index.vue'),
+  },
+  {
+    path: '/platfinance/bill',
+    name: 'platfinance_bill',
+    meta: { title: '平台管理-账单管理' },
+    component: () => import(/* webpackChunkName: "platfinance_bill" */ '@/views/platfinance/bill/index.vue'),
+  },
+];

+ 38 - 0
src/router/module/platmanag.js

@@ -0,0 +1,38 @@
+export default [
+  {
+    path: '/platmanag/goodsTags',
+    name: 'platmanag_goodsTags',
+    meta: { title: '平台管理-商品标签设置' },
+    component: () => import(/* webpackChunkName: "platmanag_goodsTags" */ '@/views/platmanag/goodsTags/index.vue'),
+  },
+  {
+    path: '/platmanag/order',
+    name: 'platmanag_order',
+    meta: { title: '平台管理-平台订单管理' },
+    component: () => import(/* webpackChunkName: "platmanag_goodsTags" */ '@/views/platmanag/order/index.vue'),
+  },
+  {
+    path: '/platmanag/order/detail_order',
+    name: 'platmanag_order_detail_order',
+    meta: { title: '平台管理-订单管理-详细信息' },
+    component: () => import(/* webpackChunkName: "platmanag_order_detail_order" */ '@/views/platmanag/order/detail_order.vue'),
+  },
+  {
+    path: '/platmanag/order/detail_orderDetail',
+    name: 'platmanag_order_detail_orderDetail',
+    meta: { title: '平台管理-订单管理-详细信息' },
+    component: () => import(/* webpackChunkName: "platmanag_order_detail_orderDetail" */ '@/views/platmanag/order/detail_orderDetail.vue'),
+  },
+  {
+    path: '/platmanag/goodsRate',
+    name: 'platmanag_goodsRate',
+    meta: { title: '平台管理-商品评价' },
+    component: () => import(/* webpackChunkName: "platmanag_goodsRate" */ '@/views/platmanag/goodsRate/index.vue'),
+  },
+  {
+    path: '/platmanag/goodsRate/detail',
+    name: 'platmanag_goodsRate_details',
+    meta: { title: '平台管理-商品评价' },
+    component: () => import(/* webpackChunkName: "platmanag_goodsRate_detail" */ '@/views/platmanag/goodsRate/detail.vue'),
+  },
+];

+ 151 - 0
src/views/platActivi/act/detail.vue

@@ -0,0 +1,151 @@
+<template>
+  <div id="form-1">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__backInRight">
+        <el-col class="top-btn">
+          <el-button type="primary" size="mini" @click="toBack()">返回</el-button>
+        </el-col>
+        <el-col :span="24" class="one">
+          <data-form :span="24" :fields="fields" v-model="form" :rules="rules" @save="onSubmit">
+            <template #act_time>
+              <el-form ref="act_time" :model="act_time" label-width="80px">
+                <el-form-item>
+                  <el-input v-model="act_time.value"></el-input>
+                </el-form-item>
+                <el-form-item label="是否显示">
+                  <el-select v-model="act_time.is_use" placeholder="请选择">
+                    <el-option v-for="i in isuseList" :key="i.model" :label="i.label" :value="i.value"></el-option>
+                  </el-select>
+                </el-form-item>
+              </el-form>
+            </template>
+            <template #content>
+              <el-form ref="content" :model="content" label-width="80px">
+                <el-form-item>
+                  <editor v-model="content.value" url="/files/point/act/upload" />
+                </el-form-item>
+                <el-form-item label="是否显示">
+                  <el-select v-model="content.is_use" placeholder="请选择">
+                    <el-option v-for="i in isuseList" :key="i.model" :label="i.label" :value="i.value"></el-option>
+                  </el-select>
+                </el-form-item>
+              </el-form>
+            </template>
+            <template #is_use>
+              <el-option v-for="i in isuseList" :key="i.model" :label="i.label" :value="i.value"></el-option>
+            </template>
+            <template #show_index>
+              <el-option v-for="i in isuseList" :key="i.model" :label="i.label" :value="i.value"></el-option>
+            </template>
+          </data-form>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+const _ = require('lodash');
+const moment = require('moment');
+import { mapState, mapGetters, createNamespacedHelpers } from 'vuex';
+const { mapActions } = createNamespacedHelpers('platformAct');
+const { mapActions: dictData } = createNamespacedHelpers('dictData');
+
+export default {
+  name: 'form-1',
+  props: {},
+  components: {
+    editor: () => import('@/components/editor.vue'),
+  },
+  data: function () {
+    return {
+      form: {},
+      act_time: {},
+      content: {},
+      rules: {
+        label: [{ required: true, message: '请输入活动标题', trigger: 'blur' }],
+        is_use: [{ required: true, message: '请选择是否开启', trigger: 'change' }],
+      },
+      fields: [
+        { label: '活动标题', model: 'title' },
+        { label: '活动时间', model: 'act_time', custom: true },
+        { label: '活动说明', model: 'content', custom: true },
+        { label: '分享图片(237*190)', model: 'share', type: 'upload', limit: 1, url: '/files/point/act/upload' },
+        { label: '封面图片', model: 'cover', type: 'upload', limit: 1, url: '/files/point/act/upload' },
+        { label: '是否在首页展示', model: 'show_index', type: 'select' },
+        { label: '是否开启', model: 'is_use', type: 'select' },
+      ],
+      // 是否使用
+      isuseList: [],
+    };
+  },
+  async created() {
+    await this.searchOther();
+    await this.search();
+  },
+  methods: {
+    ...dictData({ dictQuery: 'query' }),
+    ...mapActions(['fetch', 'create', 'update']),
+    // 查询
+    async search() {
+      if (this.id) {
+        let res = await this.fetch(this.id);
+        if (this.$checkRes(res)) {
+          this.$set(this, `form`, res.data);
+          this.$set(this, `act_time`, res.data.act_time);
+          this.$set(this, `content`, res.data.content);
+        }
+      } else {
+        this.$set(this, `form`, { is_use: '0', show_index: '0' });
+        this.$set(this.act_time, `is_use`, '0');
+        this.$set(this.content, `is_use`, '0');
+      }
+    },
+    // 提交
+    async onSubmit({ data }) {
+      let res;
+      data.act_time = this.act_time;
+      data.content = this.content;
+      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();
+      }
+    },
+    // 查询其他信息
+    async searchOther() {
+      let res;
+      // 是否使用
+      res = await this.dictQuery({ code: 'use' });
+      if (this.$checkRes(res)) {
+        this.$set(this, `isuseList`, res.data);
+      }
+    },
+    // 返回
+    toBack() {
+      window.history.go('-1');
+    },
+  },
+  computed: {
+    id() {
+      return this.$route.query.id;
+    },
+    status() {
+      return this.$route.query.status;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) { },
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 130 - 0
src/views/platActivi/act/goods.vue

@@ -0,0 +1,130 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__backInRight">
+        <el-col :span="24" class="one"> <span>活动标题</span> </el-col>
+        <el-col :span="24" class="two">
+          <!-- <search-1 :form="searchForm" @onSubmit="search" @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
+            :select="true"
+            :selected="selected"
+            @handleSelect="handleSelect"
+            :fields="fields"
+            :opera="opera"
+            @query="search"
+            :data="list"
+            :total="total"
+            @del="toDel"
+          >
+          </data-table>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+const _ = require('lodash');
+import { mapState, mapGetters, createNamespacedHelpers } from 'vuex';
+const { mapActions } = createNamespacedHelpers('goodsJoinAct');
+const { mapActions: dictData } = createNamespacedHelpers('dictData');
+export default {
+  name: 'index',
+  props: {},
+  components: {
+    // search1: () => import('./parts/search-1.vue'),
+  },
+  data: function () {
+    const that = this;
+    return {
+      // 列表
+      opera: [{ label: '删除', method: 'del', confirm: true, type: 'danger' }],
+      fields: [
+        { label: '活动标题', model: 'title' },
+        { label: '活动时间', model: 'act_time.value' },
+      ],
+      list: [],
+      total: 0,
+      // 查询
+      searchForm: {},
+      // 多选值
+      selected: [],
+    };
+  },
+  async created() {
+    await this.search();
+  },
+  methods: {
+    ...dictData({ dictQuery: 'query' }),
+    ...mapActions(['query', 'fetch', 'create', 'update', 'delete']),
+    // 查询
+    async search({ skip = 0, limit = 10, ...info } = {}) {
+      const condition = _.cloneDeep(this.searchForm);
+      let res = await this.query({ skip, limit, ...condition, ...info });
+      if (this.$checkRes(res)) {
+        this.$set(this, 'list', res.data);
+        this.$set(this, 'total', res.total);
+      }
+    },
+    // 新增
+    toAdd() {
+      this.$router.push({ path: '/platActivi/act/goosDetail' });
+    },
+    // 删除
+    async toDel({ data }) {
+      let res = await this.delete(data._id);
+      if (this.$checkRes(res)) {
+        this.$message({ type: `success`, message: `刪除信息成功` });
+        this.search();
+      }
+    },
+    // // 重置
+    // toClose() {
+    //   this.searchForm = {};
+    //   this.search();
+    // },
+    // 多选
+    handleSelect(data) {
+      this.$set(this, `selected`, 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;
+  }
+}
+</style>

+ 157 - 0
src/views/platActivi/act/goodsDetail.vue

@@ -0,0 +1,157 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__backInRight">
+        <el-col :span="24" class="one"> <span>平台商品</span> </el-col>
+        <el-col :span="24" class="two">
+          <el-autocomplete v-model="goods" :fetch-suggestions="querySearchAsync" placeholder="请输入商品名称" @select="handleSelect"></el-autocomplete>
+        </el-col>
+        <el-col :span="24" class="thr">
+          <el-button type="primary" size="mini" @click="toBack()">返回</el-button>
+        </el-col>
+        <el-col :span="24" class="four">
+          <data-table :fields="fields" :opera="opera" @query="search" :data="list" :total="total" @add="toAdd"> </data-table>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+const _ = require('lodash');
+import { mapState, mapGetters, createNamespacedHelpers } from 'vuex';
+const { mapActions } = createNamespacedHelpers('goodsJoinAct');
+const { mapActions: dictData } = createNamespacedHelpers('dictData');
+const { mapActions: goods } = createNamespacedHelpers('goods');
+export default {
+  name: 'index',
+  props: {},
+  components: {},
+  data: function () {
+    const that = this;
+    return {
+      // 列表
+      opera: [{ label: '添加', method: 'add' }],
+      fields: [
+        { label: '商品名称', model: 'name' },
+        { label: '店铺名称', model: 'shop.name' },
+        { label: '浏览量', model: 'view_num' },
+        {
+          label: '商品状态',
+          model: 'status',
+          format: (i) => {
+            let data = that.statusList.find((f) => f.value == i);
+            if (data) return data.label;
+            else return '暂无';
+          },
+        },
+      ],
+      list: [],
+      total: 0,
+      // 商品搜索
+      goods: '',
+      goodsList: [],
+      timeout: null,
+      // 商品状态
+      statusList: [],
+    };
+  },
+  async created() {
+    await this.searchOther();
+    await this.search();
+  },
+  methods: {
+    ...dictData({ dictQuery: 'query' }),
+    ...goods({ gQuery: 'query' }),
+    ...mapActions(['query', 'fetch', 'create', 'update', 'delete']),
+    // 查询
+    async search() {
+      let res = await this.gQuery();
+      if (this.$checkRes(res)) {
+        for (const val of res.data) {
+          val.value = val.name;
+        }
+        this.$set(this, 'goodsList', res.data);
+      }
+    },
+    // 点击选中
+    handleSelect(item) {
+      this.list.push(item);
+      this.$set(this, 'total', 1);
+    },
+    //获取搜索商品信息
+    querySearchAsync(queryString, cb) {
+      var goodsList = this.goodsList;
+      var results = queryString ? goodsList.filter(this.createStateFilter(queryString)) : goodsList;
+      clearTimeout(this.timeout);
+      this.timeout = setTimeout(() => {
+        cb(results);
+      }, 3000 * Math.random());
+    },
+    createStateFilter(queryString) {
+      return (state) => {
+        return state.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0;
+      };
+    },
+    // 新增
+    async toAdd({ data }) {
+      let form = { platformAct: this.id, shop: data.shop._id, goods: data._id };
+      let res = await this.create(form);
+      if (this.$checkRes(res)) {
+        this.$message({ type: `success`, message: `添加商品成功` });
+        this.toBack();
+      }
+    },
+    // 返回
+    toBack() {
+      window.history.go('-1');
+    },
+    // 查询其他信息
+    async searchOther() {
+      let res;
+      // 商品状态
+      res = await this.dictQuery({ code: 'goods_status' });
+      if (this.$checkRes(res)) {
+        this.$set(this, `statusList`, res.data);
+      }
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+    id() {
+      return this.$route.query.id;
+    },
+  },
+  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;
+    text-align: right;
+  }
+}
+</style>

+ 163 - 0
src/views/platActivi/act/index.vue

@@ -0,0 +1,163 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__backInRight">
+        <el-col :span="24" class="one"> <span>活动标题</span> </el-col>
+        <el-col :span="24" class="two">
+          <search-1 :form="searchForm" @onSubmit="search" @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 :select="true" :selected="selected" @handleSelect="handleSelect" :fields="fields" :opera="opera"
+                      @query="search" :data="list" :total="total" @edit="toEdit" @del="toDel" @manage="toManage">
+          </data-table>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+const _ = require('lodash');
+import { mapState, mapGetters, createNamespacedHelpers } from 'vuex';
+const { mapActions } = createNamespacedHelpers('platformAct');
+const { mapActions: dictData } = createNamespacedHelpers('dictData');
+export default {
+  name: 'index',
+  props: {},
+  components: {
+    search1: () => import('./parts/search-1.vue'),
+  },
+  data: function () {
+    const that = this;
+    return {
+      // 列表
+      opera: [
+        { label: '修改', method: 'edit' },
+        { label: '商品管理', method: 'manage' },
+        { label: '删除', method: 'del', confirm: true, type: 'danger' },
+      ],
+      fields: [
+        { label: '活动标题', model: 'title' },
+        { label: '活动时间', model: 'act_time.value' },
+        {
+          label: '是否开启',
+          model: 'is_use',
+          format: (i) => {
+            let data = that.isuseList.find((f) => f.value == i);
+            if (data) return data.label;
+            else return '暂无';
+          },
+        },
+        {
+          label: '是否在首页显示',
+          model: 'show_index',
+          format: (i) => {
+            let data = that.isuseList.find((f) => f.value == i);
+            if (data) return data.label;
+            else return '暂无';
+          },
+        },
+      ],
+      list: [],
+      total: 0,
+      // 查询
+      searchForm: {},
+      // 多选值
+      selected: [],
+      // 是否开启
+      isuseList: [],
+    };
+  },
+  async created() {
+    await this.searchOther();
+    await this.search();
+  },
+  methods: {
+    ...dictData({ dictQuery: 'query' }),
+    ...mapActions(['query', 'fetch', 'create', 'update', 'delete']),
+    // 查询
+    async search({ skip = 0, limit = 10, ...info } = {}) {
+      const condition = _.cloneDeep(this.searchForm);
+      let res = await this.query({ skip, limit, ...condition, ...info });
+      if (this.$checkRes(res)) {
+        this.$set(this, 'list', res.data);
+        this.$set(this, 'total', res.total);
+      }
+    },
+    // 新增
+    toAdd() {
+      this.$router.push({ path: '/platActivi/act/detail' });
+    },
+    // 修改
+    async toEdit({ data }) {
+      this.$router.push({ path: '/platActivi/act/detail', query: { id: data.id } });
+    },
+    // 平台管理
+    async toManage({ data }) {
+      this.$router.push({ path: '/platActivi/act/goods', query: { id: data.id } });
+    },
+    // 删除
+    async toDel({ data }) {
+      let res = await this.delete(data._id);
+      if (this.$checkRes(res)) {
+        this.$message({ type: `success`, message: `刪除信息成功` });
+        this.search();
+      }
+    },
+    // 重置
+    toClose() {
+      this.searchForm = {};
+      this.search();
+    },
+    // 多选
+    handleSelect(data) {
+      this.$set(this, `selected`, data);
+    },
+    // 查询其他信息
+    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;
+  }
+}
+</style>

+ 70 - 0
src/views/platActivi/act/parts/search-1.vue

@@ -0,0 +1,70 @@
+<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="title">
+              <el-input v-model="form.title" placeholder="请输入活动标题" size="small"></el-input>
+            </el-form-item>
+          </el-col>
+          <!-- <el-col :span="6">
+            <el-form-item label="编码" prop="value">
+              <el-input v-model="form.value" 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 } },
+  components: {},
+  data: function () {
+    return {};
+  },
+  created() {},
+  methods: {
+    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>

+ 119 - 0
src/views/platActivi/actTags/detail.vue

@@ -0,0 +1,119 @@
+<template>
+  <div id="form-1">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__backInRight">
+        <el-col class="top-btn">
+          <el-button type="primary" size="mini" @click="toBack()">返回</el-button>
+        </el-col>
+        <el-col :span="24" class="one">
+          <data-form :span="24" :fields="fields" v-model="form" :rules="rules" @save="onSubmit">
+            <template #status>
+              <el-option v-for="i in statusList" :key="i.model" :label="i.label" :value="i.value"></el-option>
+            </template>
+            <template #show_index>
+              <el-option v-for="i in statusList" :key="i.model" :label="i.label" :value="i.value"></el-option>
+            </template>
+          </data-form>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+const _ = require('lodash');
+const moment = require('moment');
+import { mapState, mapGetters, createNamespacedHelpers } from 'vuex';
+const { mapActions } = createNamespacedHelpers('actTags');
+const { mapActions: dictData } = createNamespacedHelpers('dictData');
+
+export default {
+  name: 'form-1',
+  props: {},
+  components: {},
+  data: function () {
+    return {
+      form: {},
+      rules: {
+        label: [{ required: true, message: '请输入活动标签', trigger: 'blur' }],
+        value: [{ required: false, message: '请输入编码', trigger: 'blur' }],
+        status: [{ required: true, message: '请选择状态', trigger: 'change' }],
+      },
+      fields: [
+        { label: '活动标签', model: 'label' },
+        { label: '编码', model: 'value' },
+        { label: '排序', model: 'sort', type: 'number' },
+        { label: '状态', model: 'status', type: 'select' },
+        { label: '标签图片', model: 'file', type: 'upload', url: '/files/point/actTags/upload' },
+        { label: '是否在首页展示', model: 'show_index', type: 'select' },
+      ],
+      // 类型
+      typeList: [],
+      // 是否使用
+      statusList: [],
+    };
+  },
+  async created() {
+    await this.searchOther();
+    await this.search();
+  },
+  methods: {
+    ...dictData({ dictQuery: 'query' }),
+    ...mapActions(['fetch', 'create', 'update']),
+    // 查询
+    async search() {
+      if (this.id) {
+        let res = await this.fetch(this.id);
+        if (this.$checkRes(res)) {
+          this.$set(this, `form`, res.data);
+        }
+      } else {
+        this.$set(this, `form`, { status: '0', show_index: '0' });
+      }
+    },
+    // 提交
+    async onSubmit({ 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();
+      }
+    },
+    // 查询其他信息
+    async searchOther() {
+      let res;
+      // 是否使用
+      res = await this.dictQuery({ code: 'status' });
+      if (this.$checkRes(res)) {
+        this.$set(this, `statusList`, res.data);
+      }
+    },
+    // 返回
+    toBack() {
+      window.history.go('-1');
+    },
+  },
+  computed: {
+    id() {
+      return this.$route.query.id;
+    },
+    status() {
+      return this.$route.query.status;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 168 - 0
src/views/platActivi/actTags/index.vue

@@ -0,0 +1,168 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__backInRight">
+        <el-col :span="24" class="one"> <span>活动标签</span> </el-col>
+        <el-col :span="24" class="two">
+          <search-1 :form="searchForm" @onSubmit="search" @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
+            :select="true"
+            :selected="selected"
+            @handleSelect="handleSelect"
+            :fields="fields"
+            :opera="opera"
+            @query="search"
+            :data="list"
+            :total="total"
+            @edit="toEdit"
+            @del="toDel"
+          >
+          </data-table>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+const _ = require('lodash');
+import { mapState, mapGetters, createNamespacedHelpers } from 'vuex';
+const { mapActions } = createNamespacedHelpers('actTags');
+const { mapActions: dictData } = createNamespacedHelpers('dictData');
+export default {
+  name: 'index',
+  props: {},
+  components: {
+    search1: () => import('./parts/search-1.vue'),
+  },
+  data: function () {
+    const that = this;
+    return {
+      // 列表
+      opera: [
+        { label: '修改', method: 'edit' },
+        { label: '删除', method: 'del', confirm: true, type: 'danger' },
+      ],
+      fields: [
+        { label: '活动标签', model: 'label' },
+        { label: '编码', model: 'value' },
+        {
+          label: '是否正在使用',
+          model: 'status',
+          format: (i) => {
+            let data = that.statusList.find((f) => f.value == i);
+            if (data) return data.label;
+            else return '暂无';
+          },
+        },
+        {
+          label: '是否在首页显示',
+          model: 'show_index',
+          format: (i) => {
+            let data = that.statusList.find((f) => f.value == i);
+            if (data) return data.label;
+            else return '暂无';
+          },
+        },
+      ],
+      list: [],
+      total: 0,
+      // 查询
+      searchForm: {},
+      // 多选值
+      selected: [],
+      // 是否使用
+      statusList: [],
+    };
+  },
+  async created() {
+    await this.searchOther();
+    await this.search();
+  },
+  methods: {
+    ...dictData({ dictQuery: 'query' }),
+    ...mapActions(['query', 'fetch', 'create', 'update', 'delete']),
+    // 查询
+    async search({ skip = 0, limit = 10, ...info } = {}) {
+      const condition = _.cloneDeep(this.searchForm);
+      let res = await this.query({ skip, limit, ...condition, ...info });
+      if (this.$checkRes(res)) {
+        this.$set(this, 'list', res.data);
+        this.$set(this, 'total', res.total);
+      }
+    },
+    // 新增
+    toAdd() {
+      this.$router.push({ path: '/platActivi/actTags/detail' });
+    },
+    // 修改
+    async toEdit({ data }) {
+      this.$router.push({ path: '/platActivi/actTags/detail', query: { id: data.id } });
+    },
+    // 删除
+    async toDel({ data }) {
+      let res = await this.delete(data._id);
+      if (this.$checkRes(res)) {
+        this.$message({ type: `success`, message: `刪除信息成功` });
+        this.search();
+      }
+    },
+    // 重置
+    toClose() {
+      this.searchForm = {};
+      this.search();
+    },
+    // 多选
+    handleSelect(data) {
+      this.$set(this, `selected`, data);
+    },
+    // 查询其他信息
+    async searchOther() {
+      let res;
+      // 是否使用
+      res = await this.dictQuery({ code: 'status' });
+      if (this.$checkRes(res)) {
+        this.$set(this, `statusList`, 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;
+  }
+}
+</style>

+ 70 - 0
src/views/platActivi/actTags/parts/search-1.vue

@@ -0,0 +1,70 @@
+<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="label">
+              <el-input v-model="form.label" placeholder="请输入活动标签" size="small"></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col :span="6">
+            <el-form-item label="编码" prop="value">
+              <el-input v-model="form.value" 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 } },
+  components: {},
+  data: function () {
+    return {};
+  },
+  created() {},
+  methods: {
+    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>

+ 331 - 0
src/views/platActivi/coupon/detail.vue

@@ -0,0 +1,331 @@
+<template>
+  <div id="form-1">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__backInRight">
+        <el-col class="top-btn">
+          <el-button type="primary" size="mini" @click="toBack()">返回</el-button>
+        </el-col>
+        <el-col :span="12">
+          <el-form :model="form" :rules="rules" ref="form" label-width="180px">
+            <el-col :span="24">
+              <el-form-item label="发行方" prop="issue">
+                <el-select v-model="form.issue" clearable filterable placeholder="请选择发行方" size="small" style="width: 100%">
+                  <el-option v-for="i in issueList" :key="i.label" :label="i.label" :value="i.value"> </el-option>
+                </el-select>
+              </el-form-item>
+            </el-col>
+            <el-col :span="24">
+              <el-form-item label="店铺" prop="shop" style="display: none">
+                <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="24">
+              <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">
+              <el-form-item label="优惠券数量" prop="num">
+                <el-input v-model="form.num" placeholder="请输入优惠券数量" type="number" size="small"></el-input>
+              </el-form-item>
+            </el-col>
+            <el-col :span="24">
+              <el-form-item label="是否使用" prop="status">
+                <el-select v-model="form.status" clearable filterable placeholder="请选择是否使用" size="small" style="width: 100%">
+                  <el-option v-for="i in statusList" :key="i.label" :label="i.label" :value="i.value"> </el-option>
+                </el-select>
+              </el-form-item>
+            </el-col>
+            <!-- 减免方式 -->
+            <el-col :span="24">
+              <el-form-item label="减免方式" prop="discount_type">
+                <el-select v-model="form.discount_type" clearable filterable placeholder="请选择减免方式" size="small" style="width: 100%">
+                  <el-option v-for="i in discount_typeList" :key="i.label" :label="i.label" :value="i.value"> </el-option>
+                </el-select>
+              </el-form-item>
+            </el-col>
+            <el-col :span="24" v-if="form.discount_type == 'min' && form.discount_type">
+              <el-form-item label="订单最低消费金额" prop="limit">
+                <el-input v-model="form.limit" placeholder="请输入订单最低消费金额" type="number" size="small"></el-input>
+              </el-form-item>
+            </el-col>
+            <el-col :span="24" v-if="form.discount_type == 'min' && form.discount_type">
+              <el-form-item label="满足条件后优惠的金额" prop="min">
+                <el-input v-model="form.min" placeholder="请输入满足条件后优惠的金额" type="number" size="small"></el-input>
+              </el-form-item>
+            </el-col>
+            <el-col :span="24" v-if="form.discount_type == 'discount' && form.discount_type">
+              <el-form-item label="订单最低消费金额" prop="limit">
+                <el-input v-model="form.limit" placeholder="请输入订单最低消费金额" type="number" size="small"></el-input>
+              </el-form-item>
+            </el-col>
+            <el-col :span="24" v-if="form.discount_type == 'discount' && form.discount_type">
+              <el-form-item label="几折" prop="min">
+                <el-input v-model="form.min" placeholder="请输入X折的X" type="number" size="small"></el-input>
+              </el-form-item>
+            </el-col>
+            <el-col :span="24" v-if="form.discount_type == 'discount' && form.discount_type">
+              <el-form-item label="折扣减免的最大金额" prop="discount_type_max">
+                <el-input v-model="form.discount_type_max" placeholder="请输入折扣减免的最大金额" type="number" size="small"></el-input>
+              </el-form-item>
+            </el-col>
+            <!-- 使用限制 -->
+            <el-col :span="24">
+              <el-form-item label="使用限制" prop="use_limit">
+                <el-select v-model="form.use_limit" clearable filterable placeholder="请选择使用限制" size="small" style="width: 100%">
+                  <el-option v-for="i in use_limitList" :key="i.label" :label="i.label" :value="i.value"> </el-option>
+                </el-select>
+              </el-form-item>
+            </el-col>
+            <el-col :span="24" v-if="form.use_limit == 'tags' && form.use_limit">
+              <el-form-item label="商品类型" prop="tags">
+                <el-cascader
+                  v-model="form.tags"
+                  :options="tagsList"
+                  :props="props"
+                  clearable
+                  filterable
+                  placeholder="请选择商品类型"
+                  :show-all-levels="false"
+                ></el-cascader>
+              </el-form-item>
+            </el-col>
+            <!-- 领取限制 -->
+            <el-col :span="24">
+              <el-form-item label="领取限制" prop="get_limit">
+                <el-select v-model="form.get_limit" clearable filterable placeholder="请选择领取限制" size="small" style="width: 100%">
+                  <el-option v-for="i in get_limitList" :key="i.label" :label="i.label" :value="i.value"> </el-option>
+                </el-select>
+              </el-form-item>
+            </el-col>
+            <el-col :span="24" v-if="form.get_limit == 'max' && form.get_limit">
+              <el-form-item label="每人领取最大限制" prop="get_limit_max">
+                <el-input v-model="form.get_limit_max" placeholder="请输入每人领取最大限制" type="number" size="small"></el-input>
+              </el-form-item>
+            </el-col>
+            <!-- 失效方式 -->
+            <el-col :span="24">
+              <el-form-item label="失效方式" prop="expire_type">
+                <el-select v-model="form.expire_type" clearable filterable placeholder="请选择失效方式" size="small" style="width: 100%">
+                  <el-option v-for="i in expire_typeList" :key="i.label" :label="i.label" :value="i.value"> </el-option>
+                </el-select>
+              </el-form-item>
+            </el-col>
+            <el-col :span="24" v-if="form.expire_type == 'fixed' && form.expire_type">
+              <el-form-item label="失效配置" prop="time">
+                <el-date-picker
+                  v-model="form.time"
+                  type="datetimerange"
+                  range-separator="至"
+                  start-placeholder="生效开始日期"
+                  end-placeholder="生效结束日期"
+                  format="yyyy-MM-dd HH:mm:ss"
+                  value-format="yyyy-MM-dd HH:mm:ss"
+                >
+                </el-date-picker>
+              </el-form-item>
+            </el-col>
+            <el-col :span="24" v-if="form.expire_type == 'days' && form.expire_type">
+              <el-form-item label="失效配置" prop="days">
+                <el-input v-model="form.days" placeholder="请输入生效几天后过期" type="number" size="small"></el-input>
+              </el-form-item>
+            </el-col>
+            <el-col :span="24" class="btn">
+              <el-button type="primary" size="mini" @click="onSubmit('form')">提交</el-button>
+              <el-button type="danger" size="mini" @click="toBack()">取消</el-button>
+            </el-col>
+          </el-form>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+const _ = require('lodash');
+const moment = require('moment');
+import { mapState, mapGetters, createNamespacedHelpers } from 'vuex';
+const { mapActions } = createNamespacedHelpers('coupon');
+const { mapActions: dictData } = createNamespacedHelpers('dictData');
+const { mapActions: goodsTags } = createNamespacedHelpers('goodsTags');
+const { mapActions: shop } = createNamespacedHelpers('shop');
+export default {
+  name: 'form-1',
+  props: {},
+  components: {},
+  data: function () {
+    return {
+      form: {},
+      rules: {
+        issue: [{ required: true, message: '请选择发行方', trigger: 'change' }],
+      },
+      // 发行方
+      issueList: [],
+      // 失效方式
+      expire_typeList: [],
+      // 减免方式
+      discount_typeList: [],
+      // 领取限制
+      get_limitList: [],
+      // 使用限制
+      use_limitList: [],
+      // 商品类型
+      tagsList: [],
+      props: { multiple: true, label: 'label', value: 'code' },
+      // 是否使用
+      statusList: [],
+      // 商铺
+      shopList: [],
+      // 店铺远程搜索加载
+      loading: false,
+    };
+  },
+  async created() {
+    await this.searchOther();
+    await this.search();
+  },
+  methods: {
+    ...dictData({ dictQuery: 'query' }),
+    ...goodsTags(['tree']),
+    ...shop({ shopQuery: 'query', shopFetch: 'fetch' }),
+    ...mapActions(['fetch', 'create', 'update']),
+    // 查询
+    async search() {
+      if (this.id) {
+        let res = await this.fetch(this.id);
+        if (this.$checkRes(res)) {
+          let data = res.data;
+          data.get_limit_max = _.get(data, 'get_limit_config.max');
+          data.discount_type_max = _.get(data, 'discount_config.max');
+          data.limit = _.get(data, 'discount_config.limit');
+          data.min = _.get(data, 'discount_config.min');
+          data.tags = _.get(data, 'use_limit_config.tags');
+          data.time = _.get(data, 'expire_config.fixed[0]');
+          data.days = _.get(data, 'expire_config.days');
+          // if (data.shop) {
+          //   let res = await this.shopFetch(data.shop);
+          //   if (this.$checkRes(res)) {
+          //     data.shop = res.data.name;
+          //   }
+          // }
+          this.$set(this, `form`, data);
+        }
+      } else {
+        this.$set(this, `form`, { status: '0' });
+      }
+    },
+    // 店铺名称远程查询
+    async querySearch(value) {
+      this.loading = true;
+      let res = await this.shopQuery({ name: value });
+      if (this.$checkRes(res)) {
+        this.$set(this, 'shopList', res.data);
+      }
+      this.loading = false;
+    },
+    // 店铺远程搜索多选
+    handleSelect(value) {
+      this.$set(this.form, `shop`, value);
+    },
+    // 提交
+    onSubmit(formName) {
+      this.$refs[formName].validate(async (valid) => {
+        if (valid) {
+          let data = this.form;
+          let discount_config = { limit: data.limit, min: data.min, max: data.discount_type_max }; //减免配置
+          let use_limit_config = { tags: data.tags }; //使用配置
+          let get_limit_config = { max: data.get_limit_max }; //领取配置
+          let expire_config = { fixed: [data.time], days: data.days }; //失效配置
+          data = { ...data, discount_config, use_limit_config, get_limit_config, expire_config };
+          let res;
+          if (data._id) res = await this.update(data);
+          else res = await this.create(data);
+          if (this.$checkRes(res, '维护信息成功', `${res.errmsg}`)) this.toBack();
+        } else {
+          return false;
+        }
+      });
+    },
+    // 查询其他信息
+    async searchOther() {
+      let res;
+      // 发行方
+      res = await this.dictQuery({ code: 'coupon_issue', value: '0' });
+      if (this.$checkRes(res)) {
+        this.$set(this, `issueList`, res.data);
+      }
+      // 失效方式
+      res = await this.dictQuery({ code: 'coupon_expire_type' });
+      if (this.$checkRes(res)) {
+        this.$set(this, `expire_typeList`, res.data);
+      }
+      // 减免方式
+      res = await this.dictQuery({ code: 'coupon_discount_type' });
+      if (this.$checkRes(res)) {
+        this.$set(this, `discount_typeList`, res.data);
+      }
+      // 使用限制
+      res = await this.dictQuery({ code: 'coupon_use_limit' });
+      if (this.$checkRes(res)) {
+        this.$set(this, `use_limitList`, res.data);
+      }
+      // 领取限制
+      res = await this.dictQuery({ code: 'coupon_get_limit' });
+      if (this.$checkRes(res)) {
+        this.$set(this, `get_limitList`, res.data);
+      }
+      // 商品类型
+      res = await this.tree();
+      if (this.$checkRes(res)) this.$set(this, `tagsList`, res.data);
+      // 使用状态
+      res = await this.dictQuery({ code: 'use' });
+      if (this.$checkRes(res)) {
+        this.$set(this, `statusList`, res.data);
+      }
+    },
+    // 返回
+    toBack() {
+      window.history.go('-1');
+    },
+  },
+  computed: {
+    id() {
+      return this.$route.query.id;
+    },
+  },
+  metaform() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  .one {
+    font-size: 20px;
+    margin: 10px 0 0 20%;
+    padding: 5px;
+  }
+  .btn {
+    text-align: center;
+  }
+}
+</style>

+ 208 - 0
src/views/platActivi/coupon/index.vue

@@ -0,0 +1,208 @@
+<template>
+  <div id="card-1">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__backInRight">
+        <el-col :span="24" class="one"> <span>优惠券管理</span> </el-col>
+        <el-col :span="24" class="two">
+          <search-1
+            :form="searchForm"
+            :statusList="statusList"
+            @onSubmit="search"
+            @toReset="toClose"
+            @querySearch="querySearch"
+            :shopList="shopList"
+            :discount_typeList="discount_typeList"
+          ></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
+            :select="true"
+            :selected="selected"
+            @handleSelect="handleSelect"
+            :fields="fields"
+            :opera="opera"
+            @query="search"
+            :data="list"
+            :total="total"
+            @edit="toEdit"
+            @del="toDel"
+          >
+          </data-table>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+const _ = require('lodash');
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions } = createNamespacedHelpers('coupon');
+const { mapActions: dictData } = createNamespacedHelpers('dictData');
+const { mapActions: shop } = createNamespacedHelpers('shop');
+
+export default {
+  name: 'card-1',
+  props: {},
+  components: { search1: () => import('./parts/search-1.vue') },
+  data: function () {
+    const that = this;
+    return {
+      // 查询
+      searchForm: {},
+      list: [],
+      total: 0,
+      opera: [
+        { label: '修改', method: 'edit' },
+        { label: '删除', method: 'del', confirm: true, type: 'danger' },
+      ],
+      fields: [
+        {
+          label: '发行方',
+          model: 'issue',
+          format: (i) => {
+            let data = that.issueList.find((f) => f.value == i);
+            if (data) return data.label;
+            else return '暂无';
+          },
+        },
+        // { label: '商铺', model: 'shop.name' },
+        { label: '优惠券名称', model: 'name' },
+        { label: '优惠券数量', model: 'num' },
+        {
+          label: '减免方式',
+          model: 'discount_type',
+          format: (i) => {
+            let data = that.discount_typeList.find((f) => f.value == i);
+            if (data) return data.label;
+            else return '暂无';
+          },
+        },
+        {
+          label: '是否使用',
+          model: 'status',
+          format: (i) => {
+            let data = that.statusList.find((f) => f.value == i);
+            if (data) return data.label;
+            else return '暂无';
+          },
+        },
+      ],
+      // 多选值
+      selected: [],
+      // 发行方
+      issueList: [],
+      // 是否使用
+      statusList: [],
+      // 商铺
+      shopList: [],
+      // 减免方式
+      discount_typeList: [],
+    };
+  },
+  async created() {
+    await this.search();
+    await this.searchOther();
+  },
+  methods: {
+    ...shop({ shopQuery: 'query' }),
+    ...dictData({ dictQuery: 'query' }),
+    ...mapActions(['query', 'fetch', 'create', 'update', 'delete']),
+    // 查询
+    async search({ skip = 0, limit = 10, ...info } = {}) {
+      let condition = _.cloneDeep(this.searchForm);
+      let res = await this.query({ skip, limit, ...condition, ...info });
+      if (this.$checkRes(res)) {
+        this.$set(this, 'list', res.data);
+        this.$set(this, 'total', res.total);
+      }
+    },
+    // 新增
+    toAdd() {
+      this.$router.push({ path: '/platActivi/coupon/detail' });
+    },
+    // 修改
+    async toEdit({ data }) {
+      this.$router.push({ path: '/platActivi/coupon/detail', query: { id: data.id } });
+    },
+    async toDel({ data }) {
+      let res = await this.delete(data._id);
+      if (this.$checkRes(res)) {
+        this.$message({ type: `success`, message: `刪除信息成功` });
+        this.search();
+      }
+    },
+    toClose() {
+      this.searchForm = {};
+      this.search();
+    },
+    // 多选
+    handleSelect(data) {
+      this.$emit('handleSelect');
+    },
+    // 查询其他信息
+    async searchOther() {
+      let res;
+      // 发行方
+      res = await this.dictQuery({ code: 'coupon_issue', value: '0' });
+      if (this.$checkRes(res)) {
+        this.$set(this, `issueList`, res.data);
+      }
+      // 使用状态
+      res = await this.dictQuery({ code: 'use' });
+      if (this.$checkRes(res)) {
+        this.$set(this, `statusList`, res.data);
+      }
+
+      // 减免方式
+      res = await this.dictQuery({ code: 'coupon_discount_type' });
+      if (this.$checkRes(res)) {
+        this.$set(this, `discount_typeList`, res.data);
+      }
+    },
+    // 店铺名称远程查询
+    async querySearch(value) {
+      let res = await this.shopQuery({ name: value });
+      if (this.$checkRes(res)) {
+        this.$set(this, 'shopList', 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;
+  }
+}
+</style>

+ 111 - 0
src/views/platActivi/coupon/parts/search-1.vue

@@ -0,0 +1,111 @@
+<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="6">
+            <el-form-item label="减免方式" prop="discount_type">
+              <el-select v-model="form.discount_type" clearable filterable placeholder="请选择减免方式" size="small" style="width: 100%">
+                <el-option v-for="i in discount_typeList" :key="i.label" :label="i.label" :value="i.value"> </el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+
+          <el-col :span="6">
+            <el-form-item label="是否使用" prop="status">
+              <el-select v-model="form.status" clearable filterable placeholder="请选择" style="width: 100%" size="small">
+                <el-option v-for="i in statusList" :key="i.label" :label="i.label" :value="i.value"></el-option>
+              </el-select>
+            </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>

+ 137 - 0
src/views/platSettings/banner/detail.vue

@@ -0,0 +1,137 @@
+<template>
+  <div id="form-1">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__backInRight">
+        <el-col class="top-btn">
+          <el-button type="primary" size="mini" @click="toBack()">返回</el-button>
+        </el-col>
+        <el-col :span="24" class="one">
+          <data-form :span="24" :fields="fields" v-model="form" :rules="rules" @save="onSubmit">
+            <template #type>
+              <el-option v-for="i in typeList" :key="i.model" :label="i.label" :value="i.value"></el-option>
+            </template>
+            <template #status>
+              <el-option v-for="i in statusList" :key="i.model" :label="i.label" :value="i.value"></el-option>
+            </template>
+            <template #content>
+              <editor v-model="form.content" url="/files/point/banner/upload" />
+            </template>
+          </data-form>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+const _ = require('lodash');
+const moment = require('moment');
+import { mapState, mapGetters, createNamespacedHelpers } from 'vuex';
+const { mapActions } = createNamespacedHelpers('banner');
+const { mapActions: dictData } = createNamespacedHelpers('dictData');
+
+export default {
+  name: 'form-1',
+  props: {},
+  components: {
+    editor: () => import('@/components/editor.vue'),
+  },
+  data: function () {
+    return {
+      form: {},
+      rules: {
+        name: [{ required: true, message: '请输入名称', trigger: 'blur' }],
+        type: [{ required: false, message: '请选择类型', trigger: 'change' }],
+        to: [{ required: false, message: '请输入跳转至', trigger: 'blur' }],
+        status: [{ required: true, message: '请选择是否正在使用', trigger: 'change' }],
+        url: [{ required: true, message: '请选择图片', trigger: 'change' }],
+      },
+      fields: [
+        { label: '名称', model: 'name' },
+        { label: '类型', model: 'type', type: 'select' },
+        { label: '跳转至', model: 'to' },
+        { label: '是否正在使用', model: 'status', type: 'select' },
+        { label: '排序', model: 'sort', type: 'number' },
+        {
+          label: '图片',
+          model: 'url',
+          type: 'upload',
+          url: '/files/point/banner/upload',
+        },
+        { label: '内容', model: 'content', custom: true },
+      ],
+      // 类型
+      typeList: [],
+      // 是否使用
+      statusList: [],
+    };
+  },
+  async created() {
+    await this.searchOther();
+    await this.search();
+  },
+  methods: {
+    ...dictData({ dictQuery: 'query' }),
+    ...mapActions(['fetch', 'create', 'update']),
+    // 查询
+    async search() {
+      if (this.id) {
+        let res = await this.fetch(this.id);
+        if (this.$checkRes(res)) {
+          this.$set(this, `form`, res.data);
+        }
+      } else {
+        this.$set(this, `form`, { status: '0' });
+      }
+    },
+    // 提交
+    async onSubmit({ 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();
+      }
+    },
+    // 查询其他信息
+    async searchOther() {
+      let res;
+      // 类型
+      res = await this.dictQuery({ code: 'banner_type' });
+      if (this.$checkRes(res)) {
+        this.$set(this, `typeList`, res.data);
+      }
+      // 是否使用
+      res = await this.dictQuery({ code: 'status' });
+      if (this.$checkRes(res)) {
+        this.$set(this, `statusList`, res.data);
+      }
+    },
+    // 返回
+    toBack() {
+      window.history.go('-1');
+    },
+  },
+  computed: {
+    id() {
+      return this.$route.query.id;
+    },
+    status() {
+      return this.$route.query.status;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 175 - 0
src/views/platSettings/banner/index.vue

@@ -0,0 +1,175 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__backInRight">
+        <el-col :span="24" class="one"> <span>广告图</span> </el-col>
+        <el-col :span="24" class="two">
+          <search-1 :form="searchForm" :typeList="typeList" @onSubmit="search" @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
+            :select="true"
+            :selected="selected"
+            @handleSelect="handleSelect"
+            :fields="fields"
+            :opera="opera"
+            @query="search"
+            :data="list"
+            :total="total"
+            @edit="toEdit"
+            @del="toDel"
+          >
+          </data-table>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+const _ = require('lodash');
+import { mapState, mapGetters, createNamespacedHelpers } from 'vuex';
+const { mapActions } = createNamespacedHelpers('banner');
+const { mapActions: dictData } = createNamespacedHelpers('dictData');
+export default {
+  name: 'index',
+  props: {},
+  components: {
+    search1: () => import('./parts/search-1.vue'),
+  },
+  data: function () {
+    const that = this;
+    return {
+      // 列表
+      opera: [
+        { label: '修改', method: 'edit' },
+        { label: '删除', method: 'del', confirm: true, type: 'danger' },
+      ],
+      fields: [
+        { label: '名称', model: 'name' },
+        {
+          label: '类型',
+          model: 'type',
+          format: (i) => {
+            let data = that.typeList.find((f) => f.value == i);
+            if (data) return data.label;
+            else return '暂无';
+          },
+        },
+        { label: '跳转到', model: 'to' },
+        {
+          label: '是否正在使用',
+          model: 'status',
+          format: (i) => {
+            let data = that.statusList.find((f) => f.value == i);
+            if (data) return data.label;
+            else return '暂无';
+          },
+        },
+      ],
+      list: [],
+      total: 0,
+      // 查询
+      searchForm: {},
+      // 多选值
+      selected: [],
+      // 类型列表
+      typeList: [],
+      // 是否使用
+      statusList: [],
+    };
+  },
+  async created() {
+    await this.searchOther();
+    await this.search();
+  },
+  methods: {
+    ...dictData({ dictQuery: 'query' }),
+    ...mapActions(['query', 'fetch', 'create', 'update', 'delete']),
+    // 查询
+    async search({ skip = 0, limit = 10, ...info } = {}) {
+      const condition = _.cloneDeep(this.searchForm);
+      let res = await this.query({ skip, limit, ...condition, ...info });
+      if (this.$checkRes(res)) {
+        this.$set(this, 'list', res.data);
+        this.$set(this, 'total', res.total);
+      }
+    },
+    // 新增
+    toAdd() {
+      this.$router.push({ path: '/platSettings/banner/detail' });
+    },
+    // 修改
+    async toEdit({ data }) {
+      this.$router.push({ path: '/platSettings/banner/detail', query: { id: data.id } });
+    },
+    // 删除
+    async toDel({ data }) {
+      let res = await this.delete(data._id);
+      if (this.$checkRes(res)) {
+        this.$message({ type: `success`, message: `刪除信息成功` });
+        this.search();
+      }
+    },
+    // 重置
+    toClose() {
+      this.searchForm = {};
+      this.search();
+    },
+    // 多选
+    handleSelect(data) {
+      this.$set(this, `selected`, data);
+    },
+    // 查询其他信息
+    async searchOther() {
+      let res;
+      // 类型
+      res = await this.dictQuery({ code: 'banner_type' });
+      if (this.$checkRes(res)) {
+        this.$set(this, `typeList`, res.data);
+      }
+      // 是否使用
+      res = await this.dictQuery({ code: 'status' });
+      if (this.$checkRes(res)) {
+        this.$set(this, `statusList`, 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;
+  }
+}
+</style>

+ 72 - 0
src/views/platSettings/banner/parts/search-1.vue

@@ -0,0 +1,72 @@
+<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="name">
+              <el-input v-model="form.name" placeholder="请输入名称" size="small"></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col :span="6">
+            <el-form-item label="类型" prop="type">
+              <el-select v-model="form.type" clearable filterable placeholder="请选择" style="width: 100%" size="small">
+                <el-option v-for="i in typeList" :key="i.label" :label="i.label" :value="i.value"></el-option>
+              </el-select>
+            </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 }, typeList: { type: Array } },
+  components: {},
+  data: function () {
+    return {};
+  },
+  created() {},
+  methods: {
+    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>

+ 64 - 0
src/views/platSettings/config/index.vue

@@ -0,0 +1,64 @@
+<template>
+  <div id="index">
+    <data-form :span="12" :fields="fields" :rules="rules" v-model="form" labelWidth="150px" @save="toSave"> </data-form>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: config } = createNamespacedHelpers('config');
+export default {
+  name: 'index',
+  props: {},
+  components: {},
+  data: function () {
+    return {
+      fields: [
+        { label: '系统名称', model: 'title' },
+        { label: 'logo', model: 'logo', type: 'upload', limit: 1, url: '/files/point/config/upload' },
+        { label: '购物赠送积分', model: 'buyPoint', type: 'number' },
+        { label: '积分计划', model: 'pointPlan' },
+        { label: '分享图片', model: 'share', type: 'upload', limit: 1, url: '/files/point/config/upload' },
+      ],
+      rules: {},
+      form: {},
+    };
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  created() {
+    this.search();
+  },
+  methods: {
+    ...config(['query', 'fetch', 'update']),
+    //执行查询
+    async search() {
+      const res = await this.fetch();
+      if (this.$checkRes(res)) {
+        this.$set(this, `form`, res.data);
+        if (this.form.config) {
+          this.form = {
+            ...this.form,
+            logo: this.form.config.logo,
+            buyPoint: this.form.config.buyPoint,
+            pointPlan: this.form.config.pointPlan,
+            share: this.form.config.share,
+          };
+        }
+      }
+    },
+    async toSave({ data }) {
+      let config = { logo: data.logo, buyPoint: data.buyPoint, pointPlan: data.pointPlan, share: data.share };
+      data.config = config;
+      const res = await this.update(data);
+      this.$checkRes(res, '操作成功', '操作失败');
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 123 - 0
src/views/platSettings/indexModule/detail.vue

@@ -0,0 +1,123 @@
+<template>
+  <div id="form-1">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__backInRight">
+        <el-col class="top-btn">
+          <el-button type="primary" size="mini" @click="toBack()">返回</el-button>
+        </el-col>
+        <el-col :span="12" class="one">
+          <data-form :span="24" :fields="fields" v-model="form" :rules="rules" @save="onSubmit">
+            <template #to_type>
+              <el-option v-for="i in typeList" :key="i.model" :label="i.label" :value="i.value"></el-option>
+            </template>
+            <template #status>
+              <el-option v-for="i in statusList" :key="i.model" :label="i.label" :value="i.value"></el-option>
+            </template>
+          </data-form>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+const _ = require('lodash');
+const moment = require('moment');
+import { mapState, mapGetters, createNamespacedHelpers } from 'vuex';
+const { mapActions } = createNamespacedHelpers('indexModule');
+const { mapActions: dictData } = createNamespacedHelpers('dictData');
+export default {
+  name: 'form-1',
+  props: {},
+  components: {},
+  data: function () {
+    return {
+      form: {},
+      rules: {
+        name: [{ required: true, message: '请输入名称', trigger: 'blur' }],
+        to_type: [{ required: false, message: '请选择类型', trigger: 'change' }],
+        to: [{ required: false, message: '请输入跳转至', trigger: 'blur' }],
+        status: [{ required: true, message: '请选择是否正在使用', trigger: 'change' }],
+        url: [{ required: true, message: '请选择图标', trigger: 'change' }],
+        sort: [{ required: true, message: '请输入排序', trigger: 'blur' }],
+      },
+      fields: [
+        { label: '名称', model: 'name' },
+        { label: '跳转类型', model: 'to_type', type: 'select' },
+        { label: '跳转至', model: 'to' },
+        { label: '是否正在使用', model: 'status', type: 'select' },
+        { label: '图标', model: 'url', type: 'upload', url: '/files/point/indexModule/upload' },
+        { label: '排序', model: 'sort', type: 'number' },
+      ],
+      typeList: [],
+      statusList: [],
+    };
+  },
+  async created() {
+    await this.searchOther();
+    await this.search();
+  },
+  methods: {
+    ...dictData({ dictQuery: 'query' }),
+    ...mapActions(['fetch', 'create', 'update']),
+    // 查询
+    async search() {
+      if (this.id) {
+        let res = await this.fetch(this.id);
+        if (this.$checkRes(res)) {
+          this.$set(this, `form`, res.data);
+        }
+      } else {
+        this.$set(this, `form`, { status: '0' });
+      }
+    },
+    // 提交
+    async onSubmit({ 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();
+      }
+    },
+    // 查询其他信息
+    async searchOther() {
+      let res;
+      // 类型
+      res = await this.dictQuery({ code: 'to_type' });
+      if (this.$checkRes(res)) {
+        this.$set(this, `typeList`, res.data);
+      }
+      res = await this.dictQuery({ code: 'status' });
+      if (this.$checkRes(res)) {
+        this.$set(this, `statusList`, res.data);
+      }
+    },
+    // 返回
+    toBack() {
+      window.history.go('-1');
+    },
+  },
+  computed: {
+    id() {
+      return this.$route.query.id;
+    },
+    status() {
+      return this.$route.query.status;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 172 - 0
src/views/platSettings/indexModule/index.vue

@@ -0,0 +1,172 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__backInRight">
+        <el-col :span="24" class="one"> <span>首页广告图标设置</span> </el-col>
+        <el-col :span="24" class="two">
+          <search-1 :form="searchForm" :typeList="typeList" @onSubmit="search" @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
+            :select="true"
+            :selected="selected"
+            @handleSelect="handleSelect"
+            :fields="fields"
+            :opera="opera"
+            @query="search"
+            :data="list"
+            :total="total"
+            @edit="toEdit"
+            @del="toDel"
+          >
+          </data-table>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+const _ = require('lodash');
+import { mapState, mapGetters, createNamespacedHelpers } from 'vuex';
+const { mapActions } = createNamespacedHelpers('indexModule');
+const { mapActions: dictData } = createNamespacedHelpers('dictData');
+export default {
+  name: 'index',
+  props: {},
+  components: {
+    search1: () => import('./parts/search-1.vue'),
+  },
+  data: function () {
+    const that = this;
+    return {
+      // 列表
+      opera: [
+        { label: '修改', method: 'edit' },
+        { label: '删除', method: 'del', confirm: true, type: 'danger' },
+      ],
+      fields: [
+        { label: '名称', model: 'name' },
+        {
+          label: '跳转类型',
+          model: 'to_type',
+          format: (i) => {
+            let data = that.typeList.find((f) => f.value == i);
+            if (data) return data.label;
+            else return '暂无';
+          },
+        },
+        { label: '跳转到', model: 'to' },
+        {
+          label: '是否正在使用',
+          model: 'status',
+          format: (i) => {
+            let data = that.statusList.find((f) => f.value == i);
+            if (data) return data.label;
+            else return '暂无';
+          },
+        },
+      ],
+      list: [],
+      total: 0,
+      // 查询
+      searchForm: {},
+      // 多选值
+      selected: [],
+      // 类型列表
+      typeList: [],
+      // 是否使用
+      statusList: [],
+    };
+  },
+  async created() {
+    await this.searchOther();
+    await this.search();
+  },
+  methods: {
+    ...dictData({ dictQuery: 'query' }),
+    ...mapActions(['query', 'fetch', 'create', 'update', 'delete']),
+    // 查询
+    async search({ skip = 0, limit = 10, ...info } = {}) {
+      const condition = _.cloneDeep(this.searchForm);
+      let res = await this.query({ skip, limit, ...condition, ...info });
+      if (this.$checkRes(res)) {
+        this.$set(this, 'list', res.data);
+        this.$set(this, 'total', res.total);
+      }
+    },
+    // 新增
+    toAdd() {
+      this.$router.push({ path: '/platSettings/indexModule/detail' });
+    },
+    // 修改
+    async toEdit({ data }) {
+      this.$router.push({ path: '/platSettings/indexModule/detail', query: { id: data.id } });
+    },
+    async toDel({ data }) {
+      let res = await this.delete(data._id);
+      if (this.$checkRes(res)) {
+        this.$message({ type: `success`, message: `刪除信息成功` });
+        this.search();
+      }
+    },
+    toClose() {
+      this.searchForm = {};
+      this.search();
+    },
+    // 多选
+    handleSelect(data) {
+      this.$set(this, `selected`, data);
+    },
+    // 查询其他信息
+    async searchOther() {
+      let res;
+      // 类型
+      res = await this.dictQuery({ code: 'to_type' });
+      if (this.$checkRes(res)) {
+        this.$set(this, `typeList`, res.data);
+      }
+      res = await this.dictQuery({ code: 'status' });
+      if (this.$checkRes(res)) {
+        this.$set(this, `statusList`, 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;
+  }
+}
+</style>

+ 73 - 0
src/views/platSettings/indexModule/parts/search-1.vue

@@ -0,0 +1,73 @@
+<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="name">
+              <el-input v-model="form.name" placeholder="请输入名称" size="small"></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col :span="6">
+            <el-form-item label="跳转类型" prop="to_type">
+              <el-select v-model="form.to_type" clearable filterable placeholder="请选择" style="width: 100%" size="small">
+                <el-option v-for="i in typeList" :key="i.label" :label="i.label" :value="i.value"></el-option>
+              </el-select>
+            </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 }, typeList: { type: Array } },
+  components: {},
+  data: function () {
+    return {};
+  },
+  created() {},
+  methods: {
+    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>

+ 82 - 0
src/views/platSettings/service/index.vue

@@ -0,0 +1,82 @@
+<template>
+  <div id="goods">
+    <el-col :span="24" class="one"> <span>客服</span> </el-col>
+    <template v-if="view === 'list'">
+      <data-table ref="dataTable" :fields="fields" :opera="opera" :data="list" :total="total" :limit="limit" @query="search" @edit="toEdit"></data-table>
+    </template>
+    <template v-else>
+      <el-row>
+        <el-col :span="24">
+          <el-button icon="el-icon-back" size="mini" @click="toBack()">返回</el-button>
+        </el-col>
+        <el-col :span="24">
+          <data-form :fields="infoFields" :rules="rules" v-model="form" labelWidth="150px" @save="toSave"> </data-form>
+        </el-col>
+      </el-row>
+    </template>
+  </div>
+</template>
+
+<script>
+const _ = require('lodash');
+import methodsUtil from '@/util/opera';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions } = createNamespacedHelpers('serviceContact');
+export default {
+  name: 'index',
+  props: {},
+  components: {},
+  data: function () {
+    return {
+      view: 'list',
+      fields: [
+        { label: '联系电话', model: 'phone' },
+        { label: '微信', model: 'wx' },
+        { label: 'QQ', model: 'qq' },
+        { label: '邮箱', model: 'email' },
+      ],
+      opera: [{ label: '修改', method: 'edit' }],
+      list: [],
+      total: 0,
+      limit: 10,
+      // info部分
+      infoFields: [
+        { label: '联系电话', model: 'phone' },
+        { label: '微信', model: 'wx' },
+        { label: 'QQ', model: 'qq' },
+        { label: '邮箱', model: 'email' },
+      ],
+      rules: {},
+      form: {},
+    };
+  },
+  created() {
+    this.searchOthers();
+    this.search();
+  },
+  methods: {
+    ...mapActions(['query', 'delete', 'fetch', 'update', 'create']),
+    ...methodsUtil,
+    async search({ skip = 0, limit = this.limit, ...info } = {}) {
+      const res = await this.query({ skip, limit, ...info });
+      if (this.$checkRes(res)) {
+        this.$set(this, `list`, res.data);
+        this.$set(this, `total`, res.total);
+      }
+    },
+    async searchOthers() {},
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.one {
+  margin: 0 0 10px 0;
+
+  span:nth-child(1) {
+    font-size: 20px;
+    font-weight: 700;
+    margin-right: 10px;
+  }
+}
+</style>

+ 200 - 0
src/views/platfinance/bill/index.vue

@@ -0,0 +1,200 @@
+<template>
+  <div id="card-1">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one">
+          <search-1 :form="searchForm" @onSubmit="search" @querySearch="querySearch" @toReset="toClose" :shopList="shopList"></search-1>
+        </el-col>
+        <el-col :span="24" v-if="afterSaleList.length != '0' || orderList.length != '0'">
+          <el-button type="primary" @click="toFile()">对账</el-button>
+        </el-col>
+        <el-col :span="24" class="two">
+          净销售额:<span>{{ info.total || '0' }}</span> 元
+        </el-col>
+        <el-col :span="24">
+          <el-tabs type="border-card">
+            <el-tab-pane label="订单">
+              <data-table :fields="orderfields" @query="search" :data="orderList" :usePage="false"> </data-table>
+            </el-tab-pane>
+            <el-tab-pane label="售后单">
+              <data-table :fields="afterSalefields" @query="search" :data="afterSaleList" :usePage="false"> </data-table>
+            </el-tab-pane>
+          </el-tabs>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+const _ = require('lodash');
+import FileSaver from 'file-saver';
+const ExcelJS = require('exceljs');
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions } = createNamespacedHelpers('getBill');
+const { mapActions: outBill } = createNamespacedHelpers('outBill');
+const { mapActions: shop } = createNamespacedHelpers('shop');
+export default {
+  name: 'card-1',
+  props: {},
+  components: { search1: () => import('./parts/search-1.vue') },
+  data: function () {
+    return {
+      searchForm: {},
+      info: {},
+      afterSaleList: [],
+      orderList: [],
+      orderfields: [
+        { label: '订单号', model: 'no' },
+        { label: '订单类型', model: 'type' },
+        { label: '支付时间', model: 'pay_time' },
+        { label: '商品', model: 'goods' },
+        { label: '规格', model: 'spec' },
+        { label: '购买数量', model: 'buy_num' },
+        { label: '单价', model: 'price' },
+        { label: '优惠金额', model: 'discount' },
+        { label: '总价', model: 'total' },
+      ],
+      afterSalefields: [
+        { label: '订单号', model: 'no' },
+        { label: '商品', model: 'goods' },
+        { label: '规格', model: 'spec' },
+        { label: '退款时间', model: 'end_time' },
+        { label: '退款金额', model: 'money' },
+      ],
+      // 多选值
+      selected: [],
+      // 自营店铺信息
+      shop: {},
+      // 店铺列表
+      shopList: [],
+    };
+  },
+  async created() {
+    await this.search();
+    await this.searchOther();
+  },
+  methods: {
+    ...shop({ shopQuery: 'query' }),
+    ...mapActions(['query', 'fetch', 'create', 'update', 'delete']),
+    ...outBill({ outQuery: 'query', outCreate: 'create' }),
+    // 查询
+    async search({ skip = 0, limit = 10, ...info } = {}) {
+      let condition = _.cloneDeep(this.searchForm);
+      if (condition.buy_time && condition.shop) {
+        condition[`start`] = _.head(condition.buy_time);
+        condition[`end`] = _.last(condition.buy_time);
+        delete condition.buy_time;
+        let res = await this.query({ skip, limit, ...condition, ...info });
+        if (this.$checkRes(res)) {
+          this.$set(this, 'info', res.data);
+          this.$set(this, 'afterSaleList', res.data.afterSaleList);
+          this.$set(this, 'orderList', res.data.orderList);
+        }
+      } else {
+        this.$message({ type: `warning`, message: `请选择查询信息` });
+      }
+    },
+    toClose() {
+      this.searchForm = {};
+      this.search();
+    },
+    // 店铺名称远程查询
+    async querySearch(value) {
+      let res = await this.shopQuery({ name: value });
+      if (this.$checkRes(res)) {
+        this.$set(this, 'shopList', res.data);
+      }
+    },
+    // 导出清单
+    toFile() {
+      const workbook = new ExcelJS.Workbook();
+      let orderList = this.orderList;
+      const worksheet_one = workbook.addWorksheet('订单');
+      let data_one = [['订单号', '订单类型', '支付时间', '商品', '规格', '购买数量', '单价', '优惠金额', '总价']];
+      for (const p1 of orderList) {
+        let p2 = [[p1.no, p1.type, p1.pay_time, p1.goods, p1.spec, p1.buy_num, p1.price, p1.discount, p1.total]];
+        data_one.push(...p2);
+      }
+      for (const val of data_one) {
+        worksheet_one.addRow(val);
+      }
+      let afterSaleList = this.afterSaleList;
+      const worksheet_two = workbook.addWorksheet('售后单');
+      let data_two = [['订单号', '商品', '规格', '退款时间', '退款金额']];
+      for (const p1 of afterSaleList) {
+        let p2 = [[p1.no, p1.goods, p1.spec, p1.end_time, p1.money]];
+        data_two.push(...p2);
+      }
+      for (const val of data_two) {
+        worksheet_two.addRow(val);
+      }
+      worksheet_one.columns.forEach(function (column, i) {
+        column.width = 20;
+      });
+      worksheet_two.columns.forEach(function (column, i) {
+        column.width = 20;
+      });
+      workbook.xlsx.writeBuffer().then((buffer) => {
+        FileSaver.saveAs(
+          new Blob([buffer], {
+            type: 'application/octet-stream',
+          }),
+          `对账单.xlsx`
+        );
+      });
+      // this.$confirm('是否确认对账?', '提示', {
+      //   confirmButtonText: '确定',
+      //   cancelButtonText: '取消',
+      //   type: 'warning',
+      // }).then(async () => {
+      //   let order = [];
+      //   for (const p1 of this.orderList) {
+      //     order.push(p1._id);
+      //   }
+      //   let afterSale = [];
+      //   for (const p1 of this.afterSaleList) {
+      //     afterSale.push(p1._id);
+      //   }
+      //   let res;
+      //   res = await this.outCreate({ order, afterSale });
+      //   if (this.$checkRes(res)) {
+      //     this.$message({ type: `success`, message: `对账成功` });
+      //   }
+      // });
+    },
+    // 查询其他信息
+    async searchOther() {},
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.one {
+  margin: 0 0 10px 0;
+}
+.two {
+  span {
+    color: red;
+  }
+}
+.title {
+  text-align: center;
+}
+.el-col {
+  margin: 10px 0;
+}
+</style>

+ 97 - 0
src/views/platfinance/bill/parts/search-1.vue

@@ -0,0 +1,97 @@
+<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="7">
+            <el-form-item label="日期" prop="buy_time">
+              <el-date-picker
+                v-model="form.buy_time"
+                type="daterange"
+                range-separator="至"
+                start-placeholder="开始日期"
+                end-placeholder="结束日期"
+                value-format="yyyy-MM-dd"
+              >
+              </el-date-picker>
+            </el-form-item>
+          </el-col>
+          <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="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 }, shopList: { 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>

+ 87 - 0
src/views/platfinance/statistics/index.vue

@@ -0,0 +1,87 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__backInRight">
+        <el-col :span="24" class="one"> <span>统计</span> </el-col>
+        <el-col :span="24">
+          <el-tabs type="border-card">
+            <el-tab-pane label="年度销售额"><card-1></card-1> </el-tab-pane>
+            <el-tab-pane label="年度下单数"><card-2></card-2></el-tab-pane>
+            <el-tab-pane label="年度付款数"><card-3></card-3></el-tab-pane>
+            <el-tab-pane label="年度退货数"><card-4></card-4></el-tab-pane>
+            <el-tab-pane label="年度退款数"><card-5></card-5></el-tab-pane>
+            <el-tab-pane label="年度换货数"><card-6></card-6></el-tab-pane>
+          </el-tabs>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+const _ = require('lodash');
+import { mapState, mapGetters, createNamespacedHelpers } from 'vuex';
+const { mapActions } = createNamespacedHelpers('todo');
+export default {
+  name: 'index',
+  props: {},
+  components: {
+    card1: () => import('./parts/card-1.vue'),
+    card2: () => import('./parts/card-2.vue'),
+    card3: () => import('./parts/card-3.vue'),
+    card4: () => import('./parts/card-4.vue'),
+    card5: () => import('./parts/card-5.vue'),
+    card6: () => import('./parts/card-6.vue'),
+  },
+  data: function () {
+    return {
+      data: {},
+    };
+  },
+  async created() {
+    await this.search();
+  },
+  methods: {
+    ...mapActions(['query', 'fetch', 'create', 'update', 'delete']),
+    async search({ skip = 0, limit = 10, ...info } = {}) {
+      let res = await this.query({ skip, limit, ...info });
+      if (this.$checkRes(res)) {
+        this.$set(this, 'data', 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;
+  }
+}
+</style>

+ 142 - 0
src/views/platfinance/statistics/parts/card-1.vue

@@ -0,0 +1,142 @@
+<template>
+  <div id="card-1">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24">
+          <el-button type="primary" size="mini" @click="totime('day')">本日</el-button>
+          <el-button type="primary" size="mini" @click="totime('week')">本周</el-button>
+          <el-button type="primary" size="mini" @click="totime('monthDay')">本月</el-button>
+          <el-button type="primary" size="mini" @click="totime('yearMonth')">本年</el-button>
+          <el-date-picker
+            v-model="time"
+            type="daterange"
+            range-separator="至"
+            start-placeholder="开始日期"
+            end-placeholder="结束日期"
+            value-format="yyyy-MM-dd"
+            style="margin: 0 12px"
+          >
+          </el-date-picker>
+          <el-button type="primary" size="mini" @click="totime(time, 1)">查询</el-button>
+        </el-col>
+        <el-col :span="24" class="two">
+          <div id="card_one" style="width: 70vw; height: 30vw; margin: 40px 0 0 0"></div>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import * as echarts from 'echarts';
+var myChart;
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions } = createNamespacedHelpers('sellTotal');
+export default {
+  name: 'index',
+  props: {},
+  components: {},
+  data: function () {
+    return {
+      xAxisList: [],
+      seriesList: [],
+      time: '',
+    };
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  async mounted() {
+    await this.search();
+  },
+  async created() {},
+  methods: {
+    ...mapActions(['query', 'fetch', 'create', 'update', 'delete']),
+    async search({ skip = 0, limit = 10, ...info } = {}) {
+      let res = await this.query({ skip, limit, type: info.time, start: info.start, end: info.end });
+      if (this.$checkRes(res)) {
+        let list = res.data;
+        let xAxisList = [];
+        let seriesList = [];
+        if (info.time == 'yearMonth') {
+          for (let i = 1; i <= 12; i++) {
+            let str = i;
+            if (i < 10) str = `0${i}`;
+            str = `-${str}-`;
+            const l = list.filter((f) => f.date.includes(str));
+            const month = `${i}月`;
+            const num = l.reduce((p, n) => p + n.money, 0);
+            xAxisList.push(month);
+            seriesList.push(num);
+          }
+        } else {
+          for (const p1 of list) {
+            xAxisList.push(p1.date);
+            seriesList.push(p1.money);
+          }
+        }
+        this.$set(this, 'xAxisList', xAxisList);
+        this.$set(this, 'seriesList', seriesList);
+      }
+    },
+    totime(time, e) {
+      if (e == '1') {
+        let start = time[0];
+        let end = time[1];
+        this.search({ start, end, time: 'custom' });
+      } else {
+        this.search({ time });
+      }
+    },
+    getEchartData(data) {
+      if (myChart != null && myChart != '' && myChart != undefined) {
+        myChart.dispose(); //销毁
+      }
+      myChart = echarts.init(document.getElementById('card_one'));
+      var option;
+      option = {
+        title: {
+          text: '年度销售额/(元)',
+        },
+        color: '#FFD700',
+        tooltip: {
+          trigger: 'axis',
+          confine: true,
+        },
+        xAxis: {
+          type: 'category',
+          data: this.xAxisList,
+          axisLabel: {
+            // 设置x轴线的属性//使x轴文字显示全
+            show: true,
+            rotate: 50,
+          },
+        },
+        yAxis: {
+          type: 'value',
+        },
+        series: [
+          {
+            data: this.seriesList,
+            type: 'bar',
+          },
+        ],
+      };
+      myChart.setOption(option);
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    seriesList: {
+      deep: true,
+      handler(val) {
+        this.getEchartData();
+      },
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 143 - 0
src/views/platfinance/statistics/parts/card-2.vue

@@ -0,0 +1,143 @@
+<template>
+  <div id="card-1">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24">
+          <el-button type="primary" size="mini" @click="totime('day')">本日</el-button>
+          <el-button type="primary" size="mini" @click="totime('week')">本周</el-button>
+          <el-button type="primary" size="mini" @click="totime('monthDay')">本月</el-button>
+          <el-button type="primary" size="mini" @click="totime('yearMonth')">本年</el-button>
+          <el-date-picker
+            v-model="time"
+            type="daterange"
+            range-separator="至"
+            start-placeholder="开始日期"
+            end-placeholder="结束日期"
+            value-format="yyyy-MM-dd"
+            style="margin: 0 12px"
+          >
+          </el-date-picker>
+          <el-button type="primary" size="mini" @click="totime(time, 1)">查询</el-button>
+        </el-col>
+        <el-col :span="24" class="two">
+          <div id="card_two" style="width: 70vw; height: 30vw; margin: 40px 0 0 0"></div>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import * as echarts from 'echarts';
+var myChart;
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions } = createNamespacedHelpers('todo');
+export default {
+  name: 'index',
+  props: {},
+  components: {},
+  data: function () {
+    return {
+      xAxisList: [],
+      seriesList: [],
+      time: '',
+    };
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  async mounted() {
+    await this.search();
+  },
+  async created() {},
+  methods: {
+    ...mapActions(['query', 'fetch', 'create', 'update', 'delete']),
+    async search({ skip = 0, limit = 10, ...info } = {}) {
+      let res = await this.query({ skip, limit, type: info.time, start: info.start, end: info.end });
+      if (this.$checkRes(res)) {
+        let list = res.data.sMarkOrder;
+        let xAxisList = [];
+        let seriesList = [];
+        if (info.time == 'yearMonth') {
+          for (let i = 1; i <= 12; i++) {
+            let str = i;
+            if (i < 10) str = `0${i}`;
+            str = `-${str}-`;
+            const l = list.filter((f) => f.date.includes(str));
+            const month = `${i}月`;
+            const num = l.reduce((p, n) => p + n.num, 0);
+            xAxisList.push(month);
+            seriesList.push(num);
+          }
+        } else {
+          for (const p1 of list) {
+            xAxisList.push(p1.date);
+            seriesList.push(p1.num);
+          }
+        }
+        this.$set(this, 'xAxisList', xAxisList);
+        this.$set(this, 'seriesList', seriesList);
+      }
+    },
+    totime(time, e) {
+      if (e == '1') {
+        let start = time[0];
+        let end = time[1];
+        this.search({ start, end, time: 'custom' });
+      } else {
+        this.search({ time });
+      }
+    },
+    getEchartData(data) {
+      if (myChart != null && myChart != '' && myChart != undefined) {
+        myChart.dispose(); //销毁
+      }
+      myChart = echarts.init(document.getElementById('card_two'));
+      var option;
+      option = {
+        title: {
+          text: '年度下单数/(单)',
+        },
+        color: '#FFD700',
+        tooltip: {
+          trigger: 'axis',
+          confine: true,
+        },
+        xAxis: {
+          type: 'category',
+          data: this.xAxisList,
+          // 设置x轴线的属性
+          //使x轴文字显示全
+          axisLabel: {
+            show: true,
+            rotate: 50,
+          },
+        },
+        yAxis: {
+          type: 'value',
+        },
+        series: [
+          {
+            data: this.seriesList,
+            type: 'line',
+          },
+        ],
+      };
+      myChart.setOption(option);
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    seriesList: {
+      deep: true,
+      handler(val) {
+        this.getEchartData();
+      },
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 145 - 0
src/views/platfinance/statistics/parts/card-3.vue

@@ -0,0 +1,145 @@
+<template>
+  <div id="card-1">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24">
+          <el-button type="primary" size="mini" @click="totime('day')">本日</el-button>
+          <el-button type="primary" size="mini" @click="totime('week')">本周</el-button>
+          <el-button type="primary" size="mini" @click="totime('monthDay')">本月</el-button>
+          <el-button type="primary" size="mini" @click="totime('yearMonth')">本年</el-button>
+          <el-date-picker
+            v-model="time"
+            type="daterange"
+            range-separator="至"
+            start-placeholder="开始日期"
+            end-placeholder="结束日期"
+            value-format="yyyy-MM-dd"
+            style="margin: 0 12px"
+          >
+          </el-date-picker>
+          <el-button type="primary" size="mini" @click="totime(time, 1)">查询</el-button>
+        </el-col>
+        <el-col :span="24" class="two">
+          <div id="card_thr" style="width: 70vw; height: 30vw; margin: 40px 0 0 0"></div>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+var myChart;
+import * as echarts from 'echarts';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions } = createNamespacedHelpers('todo');
+export default {
+  name: 'index',
+  props: {},
+  components: {},
+  data: function () {
+    return {
+      xAxisList: [],
+      seriesList: [],
+      time: '',
+    };
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  async mounted() {
+    await this.search();
+  },
+  async created() {},
+  methods: {
+    ...mapActions(['query', 'fetch', 'create', 'update', 'delete']),
+    async search({ skip = 0, limit = 10, ...info } = {}) {
+      let res = await this.query({ skip, limit, status: '1', type: info.time, start: info.start, end: info.end });
+      if (this.$checkRes(res)) {
+        let list = res.data.sMarkOrder;
+        let xAxisList = [];
+        let seriesList = [];
+        if (info.time == 'yearMonth') {
+          for (let i = 1; i <= 12; i++) {
+            let str = i;
+            if (i < 10) str = `0${i}`;
+            str = `-${str}-`;
+            const l = list.filter((f) => f.date.includes(str));
+            const month = `${i}月`;
+            const num = l.reduce((p, n) => p + n.num, 0);
+            xAxisList.push(month);
+            seriesList.push(num);
+          }
+        } else {
+          for (const p1 of list) {
+            xAxisList.push(p1.date);
+            seriesList.push(p1.num);
+          }
+        }
+        this.$set(this, 'xAxisList', xAxisList);
+        this.$set(this, 'seriesList', seriesList);
+      }
+    },
+    totime(time, e) {
+      if (e == '1') {
+        let start = time[0];
+        let end = time[1];
+        this.search({ start, end, time: 'custom' });
+      } else {
+        this.search({ time });
+      }
+    },
+    getEchartData(data) {
+      if (myChart != null && myChart != '' && myChart != undefined) {
+        myChart.dispose(); //销毁
+      }
+      myChart = echarts.init(document.getElementById('card_thr'));
+      var option;
+      option = {
+        title: {
+          text: '年度付款数/(单)',
+        },
+        color: '#FFD700',
+        tooltip: {
+          trigger: 'axis',
+          // axisPointer: { type: 'shadow' },
+          confine: true,
+          // formatter: '{b}</br>收入{c}元', // 格式化数值百分比输出
+        },
+        xAxis: {
+          type: 'category',
+          data: this.xAxisList,
+          // 设置x轴线的属性
+          //使x轴文字显示全
+          axisLabel: {
+            show: true,
+            rotate: 50,
+          },
+        },
+        yAxis: {
+          type: 'value',
+        },
+        series: [
+          {
+            data: this.seriesList,
+            type: 'bar',
+          },
+        ],
+      };
+      myChart.setOption(option);
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    seriesList: {
+      deep: true,
+      handler(val) {
+        this.getEchartData();
+      },
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 145 - 0
src/views/platfinance/statistics/parts/card-4.vue

@@ -0,0 +1,145 @@
+<template>
+  <div id="card-1">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24">
+          <el-button type="primary" size="mini" @click="totime('day')">本日</el-button>
+          <el-button type="primary" size="mini" @click="totime('week')">本周</el-button>
+          <el-button type="primary" size="mini" @click="totime('monthDay')">本月</el-button>
+          <el-button type="primary" size="mini" @click="totime('yearMonth')">本年</el-button>
+          <el-date-picker
+            v-model="time"
+            type="daterange"
+            range-separator="至"
+            start-placeholder="开始日期"
+            end-placeholder="结束日期"
+            value-format="yyyy-MM-dd"
+            style="margin: 0 12px"
+          >
+          </el-date-picker>
+          <el-button type="primary" size="mini" @click="totime(time, 1)">查询</el-button>
+        </el-col>
+        <el-col :span="24" class="two">
+          <div id="card_fou" style="width: 70vw; height: 30vw; margin: 40px 0 0 0"></div>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+var myChart;
+import * as echarts from 'echarts';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions } = createNamespacedHelpers('todo');
+export default {
+  name: 'index',
+  props: {},
+  components: {},
+  data: function () {
+    return {
+      xAxisList: [],
+      seriesList: [],
+      time: '',
+    };
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  async mounted() {
+    await this.search();
+  },
+  async created() {},
+  methods: {
+    ...mapActions(['query', 'fetch', 'create', 'update', 'delete']),
+    async search({ skip = 0, limit = 10, ...info } = {}) {
+      let res = await this.query({ skip, limit, status: '2', type: info.time, start: info.start, end: info.end });
+      if (this.$checkRes(res)) {
+        let list = res.data.sAfterSale;
+        let xAxisList = [];
+        let seriesList = [];
+        if (info.time == 'yearMonth') {
+          for (let i = 1; i <= 12; i++) {
+            let str = i;
+            if (i < 10) str = `0${i}`;
+            str = `-${str}-`;
+            const l = list.filter((f) => f.date.includes(str));
+            const month = `${i}月`;
+            const num = l.reduce((p, n) => p + n.num, 0);
+            xAxisList.push(month);
+            seriesList.push(num);
+          }
+        } else {
+          for (const p1 of list) {
+            xAxisList.push(p1.date);
+            seriesList.push(p1.num);
+          }
+        }
+        this.$set(this, 'xAxisList', xAxisList);
+        this.$set(this, 'seriesList', seriesList);
+      }
+    },
+    totime(time, e) {
+      if (e == '1') {
+        let start = time[0];
+        let end = time[1];
+        this.search({ start, end, time: 'custom' });
+      } else {
+        this.search({ time });
+      }
+    },
+    getEchartData(data) {
+      if (myChart != null && myChart != '' && myChart != undefined) {
+        myChart.dispose(); //销毁
+      }
+      myChart = echarts.init(document.getElementById('card_fou'));
+      var option;
+      option = {
+        title: {
+          text: '年度退货数/(单)',
+        },
+        color: '#FFD700',
+        tooltip: {
+          trigger: 'axis',
+          // axisPointer: { type: 'shadow' },
+          confine: true,
+          // formatter: '{b}</br>收入{c}元', // 格式化数值百分比输出
+        },
+        xAxis: {
+          type: 'category',
+          data: this.xAxisList,
+          // 设置x轴线的属性
+          //使x轴文字显示全
+          axisLabel: {
+            show: true,
+            rotate: 50,
+          },
+        },
+        yAxis: {
+          type: 'value',
+        },
+        series: [
+          {
+            data: this.seriesList,
+            type: 'line',
+          },
+        ],
+      };
+      myChart.setOption(option);
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    seriesList: {
+      deep: true,
+      handler(val) {
+        this.getEchartData();
+      },
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 145 - 0
src/views/platfinance/statistics/parts/card-5.vue

@@ -0,0 +1,145 @@
+<template>
+  <div id="card-1">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24">
+          <el-button type="primary" size="mini" @click="totime('day')">本日</el-button>
+          <el-button type="primary" size="mini" @click="totime('week')">本周</el-button>
+          <el-button type="primary" size="mini" @click="totime('monthDay')">本月</el-button>
+          <el-button type="primary" size="mini" @click="totime('yearMonth')">本年</el-button>
+          <el-date-picker
+            v-model="time"
+            type="daterange"
+            range-separator="至"
+            start-placeholder="开始日期"
+            end-placeholder="结束日期"
+            value-format="yyyy-MM-dd"
+            style="margin: 0 12px"
+          >
+          </el-date-picker>
+          <el-button type="primary" size="mini" @click="totime(time, 1)">查询</el-button>
+        </el-col>
+        <el-col :span="24" class="two">
+          <div id="card_fiv" style="width: 70vw; height: 30vw; margin: 40px 0 0 0"></div>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+var myChart;
+import * as echarts from 'echarts';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions } = createNamespacedHelpers('todo');
+export default {
+  name: 'index',
+  props: {},
+  components: {},
+  data: function () {
+    return {
+      xAxisList: [],
+      seriesList: [],
+      time: '',
+    };
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  async mounted() {
+    await this.search();
+  },
+  async created() {},
+  methods: {
+    ...mapActions(['query', 'fetch', 'create', 'update', 'delete']),
+    async search({ skip = 0, limit = 10, ...info } = {}) {
+      let res = await this.query({ skip, limit, status: '1', type: info.time, start: info.start, end: info.end });
+      if (this.$checkRes(res)) {
+        let list = res.data.sAfterSale;
+        let xAxisList = [];
+        let seriesList = [];
+        if (info.time == 'yearMonth') {
+          for (let i = 1; i <= 12; i++) {
+            let str = i;
+            if (i < 10) str = `0${i}`;
+            str = `-${str}-`;
+            const l = list.filter((f) => f.date.includes(str));
+            const month = `${i}月`;
+            const num = l.reduce((p, n) => p + n.num, 0);
+            xAxisList.push(month);
+            seriesList.push(num);
+          }
+        } else {
+          for (const p1 of list) {
+            xAxisList.push(p1.date);
+            seriesList.push(p1.num);
+          }
+        }
+        this.$set(this, 'xAxisList', xAxisList);
+        this.$set(this, 'seriesList', seriesList);
+      }
+    },
+    totime(time, e) {
+      if (e == '1') {
+        let start = time[0];
+        let end = time[1];
+        this.search({ start, end, time: 'custom' });
+      } else {
+        this.search({ time });
+      }
+    },
+    getEchartData(data) {
+      if (myChart != null && myChart != '' && myChart != undefined) {
+        myChart.dispose(); //销毁
+      }
+      myChart = echarts.init(document.getElementById('card_fiv'));
+      var option;
+      option = {
+        title: {
+          text: '年度退款数/(单)',
+        },
+        color: '#FFD700',
+        tooltip: {
+          trigger: 'axis',
+          // axisPointer: { type: 'shadow' },
+          confine: true,
+          // formatter: '{b}</br>收入{c}元', // 格式化数值百分比输出
+        },
+        xAxis: {
+          type: 'category',
+          data: this.xAxisList,
+          // 设置x轴线的属性
+          //使x轴文字显示全
+          axisLabel: {
+            show: true,
+            rotate: 50,
+          },
+        },
+        yAxis: {
+          type: 'value',
+        },
+        series: [
+          {
+            data: this.seriesList,
+            type: 'bar',
+          },
+        ],
+      };
+      myChart.setOption(option);
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    seriesList: {
+      deep: true,
+      handler(val) {
+        this.getEchartData();
+      },
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 147 - 0
src/views/platfinance/statistics/parts/card-6.vue

@@ -0,0 +1,147 @@
+<template>
+  <div id="card-1">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24">
+          <el-button type="primary" size="mini" @click="totime('day')">本日</el-button>
+          <el-button type="primary" size="mini" @click="totime('week')">本周</el-button>
+          <el-button type="primary" size="mini" @click="totime('monthDay')">本月</el-button>
+          <el-button type="primary" size="mini" @click="totime('yearMonth')">本年</el-button>
+          <el-date-picker
+            v-model="time"
+            type="daterange"
+            range-separator="至"
+            start-placeholder="开始日期"
+            end-placeholder="结束日期"
+            value-format="yyyy-MM-dd"
+            style="margin: 0 12px"
+          >
+          </el-date-picker>
+          <el-button type="primary" size="mini" @click="totime(time, 1)">查询</el-button>
+        </el-col>
+        <el-col :span="24" class="two">
+          <div id="card_six" style="width: 70vw; height: 30vw; margin: 40px 0 0 0"></div>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+var myChart;
+import * as echarts from 'echarts';
+const moment = require('moment');
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions } = createNamespacedHelpers('todo');
+export default {
+  name: 'index',
+  props: {},
+  components: {},
+  data: function () {
+    return {
+      xAxisList: [],
+      seriesList: [],
+      // 时间
+      time: '',
+    };
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  async mounted() {
+    await this.search();
+  },
+  async created() {},
+  methods: {
+    ...mapActions(['query', 'fetch', 'create', 'update', 'delete']),
+    async search({ skip = 0, limit = 10, ...info } = {}) {
+      let res = await this.query({ skip, limit, status: '3', type: info.time, start: info.start, end: info.end });
+      if (this.$checkRes(res)) {
+        let list = res.data.sAfterSale;
+        let xAxisList = [];
+        let seriesList = [];
+        if (info.time == 'yearMonth') {
+          for (let i = 1; i <= 12; i++) {
+            let str = i;
+            if (i < 10) str = `0${i}`;
+            str = `-${str}-`;
+            const l = list.filter((f) => f.date.includes(str));
+            const month = `${i}月`;
+            const num = l.reduce((p, n) => p + n.num, 0);
+            xAxisList.push(month);
+            seriesList.push(num);
+          }
+        } else {
+          for (const p1 of list) {
+            xAxisList.push(p1.date);
+            seriesList.push(p1.num);
+          }
+        }
+        this.$set(this, 'xAxisList', xAxisList);
+        this.$set(this, 'seriesList', seriesList);
+      }
+    },
+    totime(time, e) {
+      if (e == '1') {
+        let start = time[0];
+        let end = time[1];
+        this.search({ start, end, time: 'custom' });
+      } else {
+        this.search({ time });
+      }
+    },
+    getEchartData(data) {
+      if (myChart != null && myChart != '' && myChart != undefined) {
+        myChart.dispose(); //销毁
+      }
+      myChart = echarts.init(document.getElementById('card_six'));
+      var option;
+      option = {
+        title: {
+          text: '年度换货数/(单)',
+        },
+        color: '#FFD700',
+        tooltip: {
+          trigger: 'axis',
+          // axisPointer: { type: 'shadow' },
+          confine: true,
+          // formatter: '{b}</br>收入{c}元', // 格式化数值百分比输出
+        },
+        xAxis: {
+          type: 'category',
+          data: this.xAxisList,
+          // 设置x轴线的属性
+          //使x轴文字显示全
+          axisLabel: {
+            show: true,
+            rotate: 50,
+          },
+        },
+        yAxis: {
+          type: 'value',
+        },
+        series: [
+          {
+            data: this.seriesList,
+            type: 'line',
+          },
+        ],
+      };
+      myChart.setOption(option);
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    seriesList: {
+      deep: true,
+      handler(val) {
+        this.getEchartData();
+      },
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 187 - 0
src/views/platmanag/goodsRate/detail.vue

@@ -0,0 +1,187 @@
+<template>
+  <div id="form-1">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__backInRight">
+        <el-col class="top-btn">
+          <el-button type="primary" size="mini" @click="toBack()">返回</el-button>
+        </el-col>
+        <el-col :span="24" v-if="total == 0">
+          <el-empty description="该商品暂无评价"></el-empty>
+        </el-col>
+        <el-col :span="24" class="one" v-else-if="!total == 0">
+          <el-col :span="24" class="one_2">
+            <el-col :span="24" class="cont" v-for="(item, index) in list" :key="index">
+              <el-col :span="3" class="name">
+                <el-image class="icon" :src="item.customer.icon[0].url"></el-image>
+                <el-col>{{ item.customer.name }}</el-col>
+              </el-col>
+              <el-col :span="21">
+                <el-col :span="24">
+                  <el-col :span="5">
+                    <el-col :span="8">商品评分:</el-col>
+                    <el-col :span="15"><el-rate v-model="item.goods_score" disabled score-template="{item.goods_score}" :colors="colors"> </el-rate></el-col>
+                  </el-col>
+                  <el-col :span="5">
+                    <el-col :span="8">店铺评分:</el-col>
+                    <el-col :span="15"><el-rate v-model="item.shop_score" disabled score-template="{item.shop_score}" :colors="colors"> </el-rate></el-col>
+                  </el-col>
+                  <el-col :span="5">
+                    <el-col :span="8">快递评分:</el-col>
+                    <el-col :span="15">
+                      <el-rate v-model="item.transport_score" disabled score-template="{item.transport_score}" :colors="colors"> </el-rate>
+                    </el-col>
+                  </el-col>
+                </el-col>
+                <el-col>已购规格:{{ item.goodsSpec.name }}</el-col>
+                <el-col v-for="(replys, index) in item.reply" :key="index">
+                  <el-col :span="22" class="rate">买家评价: {{ replys.content }}</el-col>
+                  <el-col v-for="(file, index) in replys.file" :key="index" :span="3">
+                    <el-image :src="file.url" class="image" :preview-src-list="replys.url"></el-image>
+                  </el-col>
+                  <el-col :span="22" class="rates">商家回复:{{ replys.reply }}</el-col>
+                  <el-col style="color: #999">{{ replys.time }}</el-col>
+                </el-col>
+              </el-col>
+            </el-col>
+          </el-col>
+          <el-col :span="24" class="pag">
+            <el-pagination
+              @current-change="currentChange"
+              :current-page.sync="skip"
+              :page-size="limit"
+              background
+              layout="total, prev, pager, next"
+              :total="total"
+            >
+            </el-pagination>
+          </el-col>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+const _ = require('lodash');
+const moment = require('moment');
+import { mapState, mapGetters, createNamespacedHelpers } from 'vuex';
+const { mapActions } = createNamespacedHelpers('goodsRate');
+
+export default {
+  name: 'form-1',
+  props: {},
+  components: {},
+  data: function () {
+    return {
+      list: [],
+      goods: {},
+      skip: 1,
+      total: 0,
+      limit: 5,
+      // 评分颜色
+      colors: ['#99A9BF', '#F7BA2A', '#FF0000'],
+    };
+  },
+  async created() {
+    await this.search();
+  },
+  methods: {
+    ...mapActions(['query', 'fetch', 'create', 'update']),
+    // 查询
+    async search({ skip = 0, limit = 5, ...info } = {}) {
+      info.goods = this.id;
+      let res;
+      res = await this.query({ skip, limit, ...info });
+      if (this.$checkRes(res)) {
+        for (const p1 of res.data) {
+          for (const p2 of p1.reply) {
+            let url = [];
+            if (p2.file) {
+              for (const p3 of p2.file) {
+                url.push(p3.url);
+              }
+              p2.url = url;
+            }
+          }
+        }
+        this.$set(this, 'list', res.data);
+        this.$set(this, 'total', res.total);
+      }
+    },
+    // 分页
+    currentChange(val) {
+      this.search({ skip: (val - 1) * this.limit });
+    },
+    // 返回
+    toBack() {
+      window.history.go('-1');
+    },
+  },
+  computed: {
+    id() {
+      return this.$route.query.id;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.el-col {
+  margin: 2px 0;
+}
+.one {
+  margin: 20px 0 0 0;
+  .one_1 {
+    margin: 15px 0;
+    padding: 10px;
+  }
+  .one_2 {
+    border: 1px solid #ccc;
+    padding: 10px;
+    .cont {
+      border-bottom: 1px solid rgb(238, 237, 237);
+      margin: 10px 0;
+      padding: 0 10px 10px 10px;
+      .name {
+        text-align: center;
+        .icon {
+          border-radius: 50%;
+          width: 100px;
+          height: 100px;
+        }
+      }
+      .image {
+        width: 100px;
+        height: 100px;
+        border: 1px solid #ccc;
+      }
+      .rate {
+        width: 91%;
+        color: red;
+        word-break: break-all;
+      }
+      .rates {
+        width: 91%;
+        word-break: break-all;
+      }
+      .btn {
+        margin: 8px 15px;
+      }
+    }
+  }
+  .pag {
+    text-align: right;
+    margin: 10px 0;
+  }
+}
+</style>

+ 123 - 0
src/views/platmanag/goodsRate/index.vue

@@ -0,0 +1,123 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__backInRight">
+        <el-col :span="24" class="one"> <span>商品评价</span> </el-col>
+        <el-col :span="24" class="two">
+          <search-1 :form="searchForm" @onSubmit="search" @toReset="toClose"></search-1>
+        </el-col>
+        <el-col :span="24" class="four">
+          <data-table
+            :select="true"
+            :selected="selected"
+            @handleSelect="handleSelect"
+            :fields="fields"
+            :opera="opera"
+            @query="search"
+            :data="list"
+            :total="total"
+            @edit="toEdit"
+          >
+          </data-table>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+const _ = require('lodash');
+import { mapState, mapGetters, createNamespacedHelpers } from 'vuex';
+const { mapActions: selfShop } = createNamespacedHelpers('selfShop');
+const { mapActions: goods } = createNamespacedHelpers('goods');
+const { mapActions: dictData } = createNamespacedHelpers('dictData');
+export default {
+  name: 'index',
+  props: {},
+  components: {
+    search1: () => import('./parts/search-1.vue'),
+  },
+  data: function () {
+    const that = this;
+    return {
+      // 列表
+      opera: [{ label: '查看评价', method: 'edit' }],
+      fields: [
+        { label: '商品名称', model: 'name' },
+        { label: '店铺名称', model: 'shop.name' },
+      ],
+      list: [],
+      total: 0,
+      // 查询
+      searchForm: {},
+      // 多选值
+      selected: [],
+      shop: {},
+    };
+  },
+  async created() {
+    await this.searchOther();
+    await this.search();
+  },
+  methods: {
+    ...dictData({ getDict: 'query' }),
+    ...selfShop(['getInfo', 'getGoods', 'goodsCreate']),
+    ...goods(['delete', 'fetch', 'update', 'create']),
+    async search({ skip = 0, limit = 10, ...info } = {}) {
+      let condition = _.cloneDeep(this.searchForm);
+      let res = await this.getGoods({ skip, limit, ...condition, ...info });
+      if (this.$checkRes(res)) {
+        this.$set(this, 'list', res.data);
+        this.$set(this, 'total', res.total);
+      }
+    },
+    // 修改
+    async toEdit({ data }) {
+      this.$router.push({ path: '/platmanag/goodsRate/detail', query: { id: data.id } });
+    },
+    // 重置
+    toClose() {
+      this.searchForm = {};
+      this.search();
+    },
+    // 多选
+    handleSelect(data) {
+      this.$set(this, `selected`, data);
+    },
+    async searchOther() {},
+  },
+  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;
+  }
+}
+</style>

+ 65 - 0
src/views/platmanag/goodsRate/parts/search-1.vue

@@ -0,0 +1,65 @@
+<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="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 }, typeList: { type: Array } },
+  components: {},
+  data: function () {
+    return {};
+  },
+  created() {},
+  methods: {
+    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>

+ 156 - 0
src/views/platmanag/goodsTags/index.vue

@@ -0,0 +1,156 @@
+<template>
+  <div id="index">
+    <template v-if="view === 'list'">
+      <el-row>
+        <el-col :span="24" class="btn" v-if="levelList.length > 0">
+          <el-col :span="2">
+            <el-button icon="el-icon-back" size="mini" type="primary" @click="backLevel()">返回</el-button>
+          </el-col>
+          <el-col :span="20">
+            <el-breadcrumb separator-class="el-icon-arrow-right">
+              <el-breadcrumb-item v-for="(item, index) in data" :key="index">{{ item.label }}({{ item.code }})</el-breadcrumb-item>
+            </el-breadcrumb>
+          </el-col>
+        </el-col>
+      </el-row>
+      <data-search :fields="searchFields" v-model="searchInfo" @query="search">
+        <template #status>
+          <el-option v-for="i in statusList" :key="i.model" :label="i.label" :value="i.value"></el-option>
+        </template>
+      </data-search>
+      <data-btn :fields="btnFields" @add="toAdd" />
+      <data-table ref="dataTable" :fields="fields" :opera="opera" :data="list" :total="total" @edit="toEdit" @delete="toDelete" @query="search">
+        <template #code="{ row, item }">
+          <el-link type="primary" @click="toData(row)">{{ row[item.model] }}</el-link>
+        </template>
+      </data-table>
+    </template>
+    <template v-else>
+      <el-row>
+        <el-col :span="24">
+          <el-button icon="el-icon-back" size="mini" type="primary" @click="toBack()">返回</el-button>
+        </el-col>
+        <el-col :span="24">
+          <data-form :span="12" :fields="infoFields" :rules="rules" v-model="form" labelWidth="150px" @save="toSave">
+            <template #status>
+              <el-option v-for="i in statusList" :key="i.model" :label="i.label" :value="i.value"></el-option>
+            </template>
+          </data-form>
+        </el-col>
+      </el-row>
+    </template>
+  </div>
+</template>
+
+<script>
+const _ = require('lodash');
+import methodUtil from '@/util/opera';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions } = createNamespacedHelpers('goodsTags');
+const { mapActions: dictData } = createNamespacedHelpers('dictData');
+export default {
+  name: 'index',
+  props: {},
+  components: {},
+  data: function () {
+    return {
+      view: 'list',
+      fields: [
+        { label: '显示名称', model: 'label' },
+        { label: '标签编码', model: 'code', custom: true },
+        { label: '状态', model: 'status', format: (i) => (i === '0' ? '使用中' : '已禁用') },
+      ],
+      opera: [
+        { label: '修改', method: 'edit' },
+        { label: '删除', method: 'delete', confirm: true, type: 'danger' },
+      ],
+      list: [],
+      total: 0,
+      limit: 10,
+      btnFields: [{ label: '添加', method: 'add' }],
+      defaultSearch: {},
+      searchInfo: {},
+      searchFields: [
+        { label: '显示名称', model: 'label' },
+        { label: '标签编码', model: 'code' },
+        { label: '状态', model: 'status', type: 'select' },
+      ],
+      infoFields: [
+        { label: '显示名称', model: 'label' },
+        { label: '标签编码', model: 'code' },
+        { label: '标签图片', model: 'file', type: 'upload', url: '/files/point/goodstags/upload' },
+        { label: '状态', model: 'status', type: 'select' },
+      ],
+      rules: {},
+      form: {},
+      statusList: [],
+
+      levelList: [],
+      data: [],
+    };
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  created() {
+    this.searchOthers();
+    this.search();
+  },
+  methods: {
+    ...mapActions(['query', 'fetch', 'create', 'update', 'delete']),
+    ...dictData({ getDict: 'query' }),
+    ..._.cloneDeep(methodUtil),
+    //执行查询
+    async search({ skip = 0, limit = this.limit || 10, ...others } = {}) {
+      let query = { skip, limit, ...others };
+      if (this.searchInfo && Object.keys(this.searchInfo).length > 0) query = { ...query, ...this.searchInfo };
+      if (this.defaultSearch && Object.keys(this.defaultSearch).length > 0) query = { ...query, ...this.defaultSearch };
+      if (this.levelList.length > 0) query.pid = _.last(this.levelList);
+      const res = await this.query(query);
+      if (this.$checkRes(res)) {
+        this.$set(this, `list`, res.data);
+        this.$set(this, `total`, res.total);
+      }
+    },
+    async searchOthers() {
+      const res = await this.getDict({ code: 'use' });
+      if (this.$checkRes(res)) this.$set(this, 'statusList', res.data);
+    },
+    initAddData() {
+      const pid = _.last(this.levelList);
+      const level = this.levelList.length + 1;
+      if (pid) this.form.pid = pid;
+      this.form.level = level;
+      this.form.status = '0';
+    },
+    async toData(row) {
+      const id = _.get(row, '_id');
+      this.levelList.push(id);
+      let data = this.data;
+      let res = await this.fetch(id);
+      if (this.$checkRes(res)) {
+        data.push(res.data);
+      }
+      this.search();
+    },
+    backLevel() {
+      this.levelList.pop();
+      this.data.pop();
+      this.search();
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.btn {
+  margin: 10px 10px 20px 10px;
+  .el-breadcrumb {
+    font-size: 16px;
+    line-height: 30px;
+  }
+}
+</style>

+ 177 - 0
src/views/platmanag/order/detail_order.vue

@@ -0,0 +1,177 @@
+<template>
+  <div id="form-1">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__backInRight">
+        <el-col class="top-btn">
+          <el-button type="primary" size="mini" @click="toBack()">返回</el-button>
+        </el-col>
+        <el-col :span="8" class="one">
+          <el-col :span="24" class="add">
+            <el-col :span="2">
+              <i class="el-icon-location"></i>
+            </el-col>
+            <el-col :span="22">
+              <p>{{ address.name }},{{ address.phone }}</p>
+              <p>{{ address.province }} , {{ address.city }} , {{ address.area }} , {{ address.address }}</p>
+            </el-col>
+          </el-col>
+          <el-col :span="24" v-for="(item, index) in list" :key="index">
+            <el-col :span="24" class="shop"> <i class="el-icon-s-shop"></i>{{ item.shop_name }}</el-col>
+            <el-col :span="24" v-for="(goods, index) in item.goods" :key="index">
+              <el-col :span="24" class="goods">
+                <el-col :span="6"><el-image :src="goods.goods.file[0].url"></el-image></el-col>
+                <el-col :span="18">
+                  <el-col :span="12">
+                    <p>{{ goods.goods.name }}</p>
+                    <p>规格:{{ goods.name }}</p>
+                  </el-col>
+                  <el-col :span="12" class="money">
+                    <p v-if="info.type == '0'">¥{{ goods.sell_money }}</p>
+                    <p v-else-if="info.type == '1'">¥{{ goods.group_config.money }}</p>
+                    <p>X{{ goods.buy_num }}</p>
+                  </el-col>
+                </el-col>
+              </el-col>
+              <el-col :span="24">
+                <el-col :span="6">运费</el-col>
+                <el-col :span="18" class="other" v-if="!goods.freight == '0'">{{ goods.freight }}</el-col>
+                <el-col :span="18" class="other" v-else>包邮</el-col>
+              </el-col>
+              <el-col :span="24">
+                <el-col :span="6">订单备注</el-col>
+                <el-col :span="18" class="other" v-if="item.remarks">{{ item.remarks }}</el-col>
+                <el-col :span="18" class="other" v-else>暂无备注</el-col>
+              </el-col>
+            </el-col>
+          </el-col>
+          <el-col :span="24">
+            <el-col :span="6">配送方式</el-col>
+            <el-col :span="18" class="other">快递配送</el-col>
+          </el-col>
+          <el-col :span="24" class="goods_total">
+            <el-col :span="6">商品金额</el-col>
+            <el-col :span="18" class="other">
+              <p>¥{{ total_detail.goods_total }}</p>
+            </el-col>
+          </el-col>
+          <el-col :span="24" class="goods_total">
+            <el-col :span="6">快递费</el-col>
+            <el-col :span="18" class="other">
+              <p>¥{{ total_detail.freight_total }}</p>
+            </el-col>
+          </el-col>
+          <el-col :span="24" class="goods_total">
+            <el-col :span="8">优惠后应付金额</el-col>
+            <el-col :span="16" class="other">
+              <p>¥{{ pay.pay_money }}</p>
+            </el-col>
+          </el-col>
+          <el-col :span="24">
+            <el-col :span="6">下单时间</el-col>
+            <el-col :span="18" class="other">{{ info.buy_time }}</el-col>
+          </el-col>
+          <el-col :span="24">
+            <el-col :span="6">支付时间</el-col>
+            <el-col :span="18" class="other">{{ info.pay_time || '未支付' }}</el-col>
+          </el-col>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+const _ = require('lodash');
+const moment = require('moment');
+import { mapState, mapGetters, createNamespacedHelpers } from 'vuex';
+const { mapActions } = createNamespacedHelpers('order');
+export default {
+  name: 'form-1',
+  props: {},
+  components: {},
+  data: function () {
+    return {
+      info: {},
+      address: {},
+      list: [],
+      total_detail: {},
+      typeList: [],
+      statusList: [],
+      pay: {},
+    };
+  },
+  async created() {
+    await this.search();
+  },
+  methods: {
+    ...mapActions(['query', 'fetch', 'create', 'update']),
+    // 查询
+    async search() {
+      let res = await this.fetch(this.id);
+      if (this.$checkRes(res)) {
+        this.$set(this, `info`, res.data);
+        // 地址
+        this.$set(this, `address`, res.data.address);
+        // 商品
+        this.$set(this, `list`, res.data.goods);
+        // 实付金额
+        this.$set(this, `total_detail`, res.data.total_detail);
+        this.$set(this, `pay`, res.data.pay);
+      }
+    },
+    // 返回
+    toBack() {
+      window.history.go('-1');
+    },
+  },
+  computed: {
+    id() {
+      return this.$route.query.id;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  .one {
+    margin: 10px 0 0 20%;
+    padding: 5px;
+    .add {
+      border-bottom: 2px dashed #ccc;
+      margin: 0 0 5px 0;
+      padding: 5px 0;
+    }
+    .shop {
+      padding: 4px 0;
+      font-size: 18px;
+      border-bottom: 1px solid #ccc;
+    }
+    .goods {
+      padding: 10px 0;
+      .money {
+        text-align: right;
+      }
+    }
+    .other {
+      text-align: right;
+      p {
+        color: red;
+      }
+    }
+    .el-col {
+      margin: 4px 0;
+    }
+  }
+}
+</style>

+ 341 - 0
src/views/platmanag/order/detail_orderDetail.vue

@@ -0,0 +1,341 @@
+<template>
+  <div id="form-1">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__backInRight">
+        <el-col class="top-btn">
+          <el-button type="primary" size="mini" @click="toBack()">返回</el-button>
+        </el-col>
+        <el-col :span="9" class="one">
+          <el-col :span="24" class="add">
+            <el-col :span="2">
+              <i class="el-icon-location"></i>
+            </el-col>
+            <el-col :span="22">
+              <el-col>
+                <p>{{ address.name }},{{ address.phone }}</p>
+              </el-col>
+              <el-col>
+                <p>{{ address.province }} , {{ address.city }} , {{ address.area }} , {{ address.address }}</p>
+              </el-col>
+            </el-col>
+          </el-col>
+          <el-col :span="24" class="shop"> <i class="el-icon-s-shop"></i>{{ shop.name }}</el-col>
+          <el-col :span="24" v-for="(item, index) in list" :key="index">
+            <el-col :span="24" class="goods bode">
+              <el-col :span="6"><el-image :src="item.goods.file[0].url"></el-image></el-col>
+              <el-col :span="18">
+                <el-col :span="12">
+                  <el-col>
+                    <p>{{ item.goods.name }}</p>
+                  </el-col>
+                  <el-col>
+                    <p>规格:{{ item.name }}</p>
+                  </el-col>
+                </el-col>
+                <el-col :span="12" class="money">
+                  <el-col>
+                    <p v-if="form.type == '0'">¥{{ item.sell_money }}</p>
+                    <p v-else-if="form.type == '1'">¥{{ item.group_config.money }}</p>
+                  </el-col>
+                  <el-col>
+                    <p>X{{ item.buy_num }}</p>
+                  </el-col>
+                </el-col>
+              </el-col>
+            </el-col>
+            <el-col :span="24" class="bode">
+              <el-col :span="6">运费</el-col>
+              <el-col :span="18" class="other" v-if="!item.goods.freight == '0'">{{ item.goods.freight }}</el-col>
+              <el-col :span="18" class="other" v-else>包邮</el-col>
+            </el-col>
+          </el-col>
+          <el-col :span="24" class="bode">
+            <el-col :span="6">订单备注</el-col>
+            <el-col :span="18" class="other" v-if="form.remarks">{{ form.remarks }}</el-col>
+            <el-col :span="18" class="other" v-else>暂无备注</el-col>
+          </el-col>
+          <el-col :span="24" class="bode">
+            <el-col :span="6">配送方式</el-col>
+            <el-col :span="18" class="other">快递配送</el-col>
+          </el-col>
+          <el-col :span="24" class="goods_total bode">
+            <el-col :span="6">商品金额</el-col>
+            <el-col :span="18" class="other">
+              <p>¥{{ total_detail.goods_total }}</p>
+            </el-col>
+          </el-col>
+          <el-col :span="24" class="goods_total bode">
+            <el-col :span="6">快递费</el-col>
+            <el-col :span="18" class="other">
+              <p>¥{{ total_detail.freight_total }}</p>
+            </el-col>
+          </el-col>
+          <el-col :span="24" class="goods_total bode">
+            <el-col :span="8">优惠后实付金额</el-col>
+            <el-col :span="16" class="other">
+              <p>¥{{ pay.pay_money }}</p>
+            </el-col>
+          </el-col>
+          <el-col :span="24" class="bode">
+            <el-col :span="6">下单时间</el-col>
+            <el-col :span="18" class="other">{{ form.buy_time }}</el-col>
+          </el-col>
+          <el-col :span="24" class="bode">
+            <el-col :span="6">支付时间</el-col>
+            <el-col :span="18" class="other">{{ form.pay_time }}</el-col>
+          </el-col>
+          <el-col :span="24" class="bode">
+            <el-col :span="6">寄出运单号</el-col>
+            <el-col :span="18" class="other">{{ transport.shop_transport_no || '暂无单号' }}</el-col>
+          </el-col>
+          <el-col :span="24" class="bode">
+            <el-col :span="6">寄出快递类型</el-col>
+            <el-col :span="18" class="other">{{ transport.shop_transport_name || '暂无快递信息' }}</el-col>
+          </el-col>
+          <el-col :span="24" class="form">
+            <el-form :model="form" ref="form" label-width="100px" class="demo-ruleForm">
+              <el-form-item
+                label="寄出运单号"
+                prop="shop_transport_no"
+                v-if="(form.status == '1' || form.status == '2') && (!transport.shop_transport_no || !transport.shop_transport_name)"
+              >
+                <el-input v-model="form.shop_transport_no" placeholder="请输入运单号,快递类型,同时填入" size="small"></el-input>
+              </el-form-item>
+              <el-form-item
+                label="快递类型"
+                prop="shop_transport_type"
+                v-if="(form.status == '1' || form.status == '2') && (!transport.shop_transport_no || !transport.shop_transport_name)"
+              >
+                <el-select
+                  v-model="form.shop_transport_type"
+                  filterable
+                  remote
+                  reserve-keyword
+                  placeholder="请选择快递类型,运单号,同时填入"
+                  :remote-method="querySearch"
+                  :loading="loading"
+                  @change="handleSelect"
+                  size="small"
+                  style="width: 100%"
+                >
+                  <el-option v-for="item in shop_transport_typeList" :key="item.id" :label="item.label" :value="item.value"> </el-option>
+                </el-select>
+              </el-form-item>
+              <el-form-item label="订单状态" prop="status">
+                <el-select v-model="form.status" clearable filterable placeholder="请选择订单状态" size="small" style="width: 100%">
+                  <el-option v-for="i in order_processList" :key="i.label" :label="i.label" :value="i.value"> </el-option>
+                </el-select>
+              </el-form-item>
+              <el-form-item>
+                <el-button type="primary" @click="onSubmit()">保存</el-button>
+              </el-form-item>
+            </el-form>
+          </el-col>
+        </el-col>
+        <el-col :span="9" class="one" v-if="transport.shop_transport_no">
+          <el-col :span="24">{{ activit.is_check || '暂无快递信息' }}</el-col>
+          <el-col :span="24">{{ transport.shop_transport_name || '暂无快递信息' }}: {{ activit.no || '暂无快递信息' }}</el-col>
+          <el-col :span="24">
+            <p>订单编号: {{ form.id }}</p>
+          </el-col>
+          <el-col :span="24">
+            <p>收货地址:{{ address.province }} , {{ address.city }} , {{ address.area }} , {{ address.address }}</p>
+          </el-col>
+          <el-col :span="24">
+            <el-timeline :reverse="reverse">
+              <el-timeline-item v-for="(activity, index) in activities" :key="index" :timestamp="activity.time" :color="activity.color">
+                {{ activity.context }}
+              </el-timeline-item>
+            </el-timeline>
+          </el-col>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+const _ = require('lodash');
+const moment = require('moment');
+import { mapState, mapGetters, createNamespacedHelpers } from 'vuex';
+const { mapActions } = createNamespacedHelpers('orderDetail');
+const { mapActions: dictData } = createNamespacedHelpers('dictData');
+const { mapActions: sot } = createNamespacedHelpers('sot');
+
+export default {
+  name: 'form-1',
+  props: {},
+  components: {},
+  data: function () {
+    return {
+      form: {},
+      // 地址
+      address: {},
+      // 实付金额
+      total_detail: {},
+      // 商铺
+      shop: {},
+      // 运单号
+      transport: {},
+      pay: {},
+      // 商品列表
+      list: [],
+      // 物流
+      reverse: false,
+      activities: [],
+      activit: {},
+      // 订单状态
+      order_processList: [],
+      // 快递类型
+      shop_transport_typeList: [],
+      loading: false,
+    };
+  },
+  async created() {
+    await this.searchOther();
+
+    await this.search();
+  },
+  methods: {
+    ...dictData({ dictQuery: 'query' }),
+    ...sot({ sotFetch: 'fetch' }),
+    ...mapActions(['query', 'fetch', 'create', 'update']),
+    // 查询
+    async search() {
+      let res;
+      res = await this.fetch(this.id);
+      if (this.$checkRes(res)) {
+        this.$set(this, `form`, res.data);
+        // 地址
+        this.$set(this, `address`, res.data.address);
+        this.$set(this, `shop`, res.data.shop);
+        // 商品
+        this.$set(this, `list`, res.data.goods);
+        // 应付金额
+        this.$set(this, `total_detail`, res.data.total_detail);
+        this.$set(this, `pay`, res.data.order.pay);
+        if (res.data.transport) {
+          let arr = await this.dictQuery({ code: 'transport_type', value: res.data.transport.shop_transport_type });
+          if (this.$checkRes(arr)) {
+            let type = arr.data.find((i) => i.value == res.data.transport.shop_transport_type);
+            if (type) res.data.transport.shop_transport_name = type.label;
+            this.$set(this, `transport`, res.data.transport);
+          }
+          res = await this.sotFetch(this.id);
+          if (this.$checkRes(res)) {
+            if (res.errcode == '0') {
+              let activities = res.data.list;
+              activities[0].color = '#0bbd87';
+              this.$set(this, `activities`, activities);
+              this.$set(this, `activit`, res.data);
+            }
+          }
+        }
+      }
+    },
+    async querySearch(value) {
+      this.loading = true;
+      let res = await this.dictQuery({ code: 'transport_type', label: value });
+      if (this.$checkRes(res)) {
+        this.$set(this, 'shop_transport_typeList', res.data);
+      }
+      this.loading = false;
+    },
+    handleSelect(value) {
+      // this.$set(this.form, `shop_transport_type`, value);
+    },
+    // 提交
+    async onSubmit() {
+      let form = this.form;
+      let transport = {};
+      let res;
+      if (form.shop_transport_no && form.shop_transport_type) {
+        transport.shop_transport_no = form.shop_transport_no;
+        transport.shop_transport_type = form.shop_transport_type;
+        form.transport = transport;
+      }
+      if (form.id) res = await this.update(form);
+      if (this.$checkRes(res)) {
+        this.$message({ type: `success`, message: `维护信息成功` });
+        this.toBack();
+      }
+    },
+    // 返回
+    toBack() {
+      window.history.go('-1');
+    },
+    // 查询其他信息
+    async searchOther() {
+      let res;
+      // 减免方式
+      res = await this.dictQuery({ code: 'order_process' });
+      if (this.$checkRes(res)) {
+        this.$set(this, `order_processList`, res.data);
+      }
+    },
+  },
+  computed: {
+    id() {
+      return this.$route.query.id;
+    },
+  },
+  metaform() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.main {
+  .one {
+    margin: 10px 0 0 5%;
+    padding: 5px;
+    .add {
+      border-bottom: 2px dashed #ccc;
+      margin: 0 0 5px 0;
+      padding: 5px 0;
+    }
+    .shop {
+      padding: 4px 0;
+      font-size: 18px;
+      border-bottom: 1px solid #ccc;
+    }
+    .goods {
+      padding: 10px 0;
+      .money {
+        text-align: right;
+      }
+    }
+    .other {
+      text-align: right;
+      p {
+        color: red;
+      }
+    }
+    .el-col {
+      margin: 3px 0;
+    }
+    .bode {
+      border-bottom: 1px solid rgb(238, 237, 237);
+    }
+    .form {
+      margin: 20px 0 0 0;
+    }
+  }
+}
+
+/deep/.el-timeline {
+  margin: 20px 0 0 0;
+  font-size: 16px;
+}
+/deep/.el-timeline-item__node:nth-child(1) {
+  background-color: green;
+}
+</style>

+ 104 - 0
src/views/platmanag/order/index.vue

@@ -0,0 +1,104 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__backInRight">
+        <el-col :span="24" class="one"> <span>订单管理</span> </el-col>
+        <el-col :span="24" class="four">
+          <el-tabs v-model="activeName" type="border-card" @tab-click="handleClick">
+            <el-tab-pane label="待付款" name="1">
+              <card-1 :statusList="statusList"></card-1>
+            </el-tab-pane>
+            <el-tab-pane label="待发货" name="2">
+              <card-2 :statusList="statusList"></card-2>
+            </el-tab-pane>
+            <el-tab-pane label="待收货" name="3">
+              <card-3 :statusList="statusList"></card-3>
+            </el-tab-pane>
+            <el-tab-pane label="已收货" name="4">
+              <card-4 :statusList="statusList"></card-4>
+            </el-tab-pane>
+          </el-tabs>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+const _ = require('lodash');
+import { mapState, mapGetters, createNamespacedHelpers } from 'vuex';
+const { mapActions: dictData } = createNamespacedHelpers('dictData');
+const { mapActions: shop } = createNamespacedHelpers('shop');
+export default {
+  name: 'index',
+  props: {},
+  components: {
+    card1: () => import('./parts/card-1.vue'),
+    card2: () => import('./parts/card-2.vue'),
+    card3: () => import('./parts/card-3.vue'),
+    card4: () => import('./parts/card-4.vue'),
+  },
+  data: function () {
+    const that = this;
+    return {
+      activeName: '2',
+      // 类型列表
+      statusList: [],
+      // 店铺列表
+      shopList: [],
+    };
+  },
+  async created() {
+    await this.searchOther();
+  },
+  methods: {
+    ...dictData({ dictQuery: 'query' }),
+    ...shop({ shopQuery: 'query' }),
+    handleClick(tab, event) {},
+    // 查询其他信息
+    async searchOther() {
+      let res;
+      // 类型
+      res = await this.dictQuery({ code: 'order_process' });
+      if (this.$checkRes(res)) {
+        this.$set(this, `statusList`, res.data);
+      }
+      res = await this.shopQuery();
+      if (this.$checkRes(res)) this.$set(this, `shopList`, 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;
+  }
+}
+</style>

+ 116 - 0
src/views/platmanag/order/parts/card-1.vue

@@ -0,0 +1,116 @@
+<template>
+  <div id="card-1">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one">
+          <search-1 :form="searchForm" @onSubmit="search" @querySearch="querySearch" @toReset="toClose" :shopList="shopList"> </search-1>
+        </el-col>
+        <data-table
+          :select="true"
+          :selected="selected"
+          @handleSelect="handleSelect"
+          :fields="fields"
+          :opera="opera"
+          @query="search"
+          :data="list"
+          :total="total"
+          @detail="toDetail"
+        >
+        </data-table>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+const _ = require('lodash');
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions } = createNamespacedHelpers('order');
+const { mapActions: shop } = createNamespacedHelpers('shop');
+export default {
+  name: 'card-1',
+  props: { statusList: { type: Array } },
+  components: { search1: () => import('./search-1.vue') },
+  data: function () {
+    return {
+      searchForm: {},
+      list: [],
+      total: 0,
+      opera: [{ label: '详情', method: 'detail' }],
+      fields: [
+        { label: '订单号', model: 'no' },
+        { label: '下单时间', model: 'buy_time' },
+        { label: '顾客', model: 'customer.name' },
+        { label: '店铺名称', model: 'goods', format: (i) => this.getShopName(i) },
+        { label: '需支付金额', model: 'real_pay' },
+      ],
+      // 多选值
+      selected: [],
+      shopList: [],
+    };
+  },
+  async created() {
+    await this.search();
+  },
+  methods: {
+    ...shop({ shopQuery: 'query' }),
+    ...mapActions(['query', 'fetch', 'create', 'update', 'delete']),
+    // 查询
+    async search({ skip = 0, limit = 10, ...info } = {}) {
+      let condition = _.cloneDeep(this.searchForm);
+      if (condition.buy_time) {
+        condition[`buy_time@start`] = _.head(condition.buy_time);
+        condition[`buy_time@end`] = _.last(condition.buy_time);
+        delete condition.buy_time;
+      }
+      info.status = '0';
+      let res = await this.query({ skip, limit, ...condition, ...info });
+      if (this.$checkRes(res)) {
+        this.$set(this, 'list', res.data);
+        this.$set(this, 'total', res.total);
+      }
+    },
+    getShopName(i) {
+      let shopname = i.map((e) => e.shop_name);
+      return shopname.join(',');
+    },
+    toDetail({ data }) {
+      this.$router.push({ path: '/platmanag/order/detail_order', query: { id: data.id } });
+    },
+    toClose() {
+      this.searchForm = {};
+      this.search();
+    },
+    // 多选
+    handleSelect(data) {
+      this.$emit('handleSelect');
+    },
+    // 店铺名称远程查询
+    async querySearch(value) {
+      let res = await this.shopQuery({ name: value });
+      if (this.$checkRes(res)) {
+        this.$set(this, 'shopList', 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>
+.one {
+  margin: 0 0 10px 0;
+}
+</style>

+ 112 - 0
src/views/platmanag/order/parts/card-2.vue

@@ -0,0 +1,112 @@
+<template>
+  <div id="card-1">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one">
+          <search-1 :form="searchForm" @onSubmit="search" @querySearch="querySearch" @toReset="toClose" :shopList="shopList"> </search-1>
+        </el-col>
+        <data-table
+          :select="true"
+          :selected="selected"
+          @handleSelect="handleSelect"
+          :fields="fields"
+          :opera="opera"
+          @query="search"
+          :data="list"
+          :total="total"
+          @detail="toDetail"
+        >
+        </data-table>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+const _ = require('lodash');
+
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions } = createNamespacedHelpers('orderDetail');
+const { mapActions: shop } = createNamespacedHelpers('shop');
+export default {
+  name: 'card-1',
+  props: { statusList: { type: Array } },
+  components: { search1: () => import('./search-1.vue') },
+  data: function () {
+    return {
+      searchForm: {},
+      list: [],
+      total: 0,
+      opera: [{ label: '详情', method: 'detail' }],
+      fields: [
+        { label: '订单号', model: 'no' },
+        { label: '下单时间', model: 'buy_time' },
+        { label: '顾客', model: 'customer.name' },
+        { label: '店铺名称', model: 'shop.name' },
+        { label: '支付金额', model: 'real_pay' },
+      ],
+      // 多选值
+      selected: [],
+      shopList: [],
+    };
+  },
+  async created() {
+    await this.search();
+  },
+  methods: {
+    ...shop({ shopQuery: 'query' }),
+    ...mapActions(['query', 'fetch', 'create', 'update', 'delete']),
+    // 查询
+    async search({ skip = 0, limit = 10, ...info } = {}) {
+      let condition = _.cloneDeep(this.searchForm);
+      if (condition.buy_time) {
+        condition[`buy_time@start`] = _.head(condition.buy_time);
+        condition[`buy_time@end`] = _.last(condition.buy_time);
+        delete condition.buy_time;
+      }
+      info.status = '1';
+      let res = await this.query({ skip, limit, ...condition, ...info });
+      if (this.$checkRes(res)) {
+        this.$set(this, 'list', res.data);
+        this.$set(this, 'total', res.total);
+      }
+    },
+    // 详情
+    toDetail({ data }) {
+      this.$router.push({ path: '/platmanag/order/detail_orderDetail', query: { id: data._id } });
+    },
+    toClose() {
+      this.searchForm = {};
+      this.search();
+    },
+    // 多选
+    handleSelect(data) {},
+    // 店铺名称远程查询
+    async querySearch(value) {
+      let res = await this.shopQuery({ name: value });
+      if (this.$checkRes(res)) {
+        this.$set(this, 'shopList', 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>
+.one {
+  margin: 0 0 10px 0;
+}
+</style>

+ 113 - 0
src/views/platmanag/order/parts/card-3.vue

@@ -0,0 +1,113 @@
+<template>
+  <div id="card-1">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one">
+          <search-1 :form="searchForm" @onSubmit="search" @querySearch="querySearch" @toReset="toClose" :shopList="shopList"> </search-1>
+        </el-col>
+        <data-table
+          :select="true"
+          :selected="selected"
+          @handleSelect="handleSelect"
+          :fields="fields"
+          :opera="opera"
+          @query="search"
+          :data="list"
+          :total="total"
+          @detail="toDetail"
+        >
+        </data-table>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+const _ = require('lodash');
+
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions } = createNamespacedHelpers('orderDetail');
+const { mapActions: shop } = createNamespacedHelpers('shop');
+export default {
+  name: 'card-1',
+  props: { statusList: { type: Array } },
+  components: { search1: () => import('./search-1.vue') },
+  data: function () {
+    return {
+      searchForm: {},
+      list: [],
+      total: 0,
+      opera: [{ label: '详情', method: 'detail' }],
+      fields: [
+        { label: '订单号', model: 'no' },
+        { label: '下单时间', model: 'buy_time' },
+        { label: '顾客', model: 'customer.name' },
+        { label: '店铺名称', model: 'shop.name' },
+        { label: '支付金额', model: 'real_pay' },
+      ],
+      // 多选值
+      selected: [],
+      shopList: [],
+    };
+  },
+  async created() {
+    await this.search();
+  },
+  methods: {
+    ...shop({ shopQuery: 'query' }),
+    ...mapActions(['query', 'fetch', 'create', 'update', 'delete']),
+    // 查询
+    async search({ skip = 0, limit = 10, ...info } = {}) {
+      let condition = _.cloneDeep(this.searchForm);
+      if (condition.buy_time) {
+        condition[`buy_time@start`] = _.head(condition.buy_time);
+        condition[`buy_time@end`] = _.last(condition.buy_time);
+        delete condition.buy_time;
+      }
+      info.status = '2';
+      let res = await this.query({ skip, limit, ...condition, ...info });
+      if (this.$checkRes(res)) {
+        this.$set(this, 'list', res.data);
+        this.$set(this, 'total', res.total);
+      }
+    },
+    toDetail({ data }) {
+      this.$router.push({ path: '/platmanag/order/detail_orderDetail', query: { id: data._id } });
+    },
+    toClose() {
+      this.searchForm = {};
+      this.search();
+    },
+    // 多选
+    handleSelect(data) {
+      this.$emit('handleSelect');
+    },
+    // 店铺名称远程查询
+    async querySearch(value) {
+      let res = await this.shopQuery({ name: value });
+      if (this.$checkRes(res)) {
+        this.$set(this, 'shopList', 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>
+.one {
+  margin: 0 0 10px 0;
+}
+</style>

+ 113 - 0
src/views/platmanag/order/parts/card-4.vue

@@ -0,0 +1,113 @@
+<template>
+  <div id="card-1">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="one">
+          <search-1 :form="searchForm" @onSubmit="search" @querySearch="querySearch" @toReset="toClose" :shopList="shopList"> </search-1>
+        </el-col>
+        <data-table
+          :select="true"
+          :selected="selected"
+          @handleSelect="handleSelect"
+          :fields="fields"
+          :opera="opera"
+          @query="search"
+          :data="list"
+          :total="total"
+          @detail="toDetail"
+        >
+        </data-table>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+const _ = require('lodash');
+
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions } = createNamespacedHelpers('orderDetail');
+const { mapActions: shop } = createNamespacedHelpers('shop');
+export default {
+  name: 'card-1',
+  props: { statusList: { type: Array } },
+  components: { search1: () => import('./search-1.vue') },
+  data: function () {
+    return {
+      searchForm: {},
+      list: [],
+      total: 0,
+      opera: [{ label: '详情', method: 'detail' }],
+      fields: [
+        { label: '订单号', model: 'no' },
+        { label: '下单时间', model: 'buy_time' },
+        { label: '顾客', model: 'customer.name' },
+        { label: '店铺名称', model: 'shop.name' },
+        { label: '支付金额', model: 'real_pay' },
+      ],
+      // 多选值
+      selected: [],
+      shopList: [],
+    };
+  },
+  async created() {
+    await this.search();
+  },
+  methods: {
+    ...shop({ shopQuery: 'query' }),
+    ...mapActions(['query', 'fetch', 'create', 'update', 'delete']),
+    // 查询
+    async search({ skip = 0, limit = 10, ...info } = {}) {
+      let condition = _.cloneDeep(this.searchForm);
+      if (condition.buy_time) {
+        condition[`buy_time@start`] = _.head(condition.buy_time);
+        condition[`buy_time@end`] = _.last(condition.buy_time);
+        delete condition.buy_time;
+      }
+      info.status = '3';
+      let res = await this.query({ skip, limit, ...condition, ...info });
+      if (this.$checkRes(res)) {
+        this.$set(this, 'list', res.data);
+        this.$set(this, 'total', res.total);
+      }
+    },
+    toDetail({ data }) {
+      this.$router.push({ path: '/platmanag/order/detail_orderDetail', query: { id: data._id } });
+    },
+    toClose() {
+      this.searchForm = {};
+      this.search();
+    },
+    // 多选
+    handleSelect(data) {
+      this.$emit('handleSelect');
+    },
+    // 店铺名称远程查询
+    async querySearch(value) {
+      let res = await this.shopQuery({ name: value });
+      if (this.$checkRes(res)) {
+        this.$set(this, 'shopList', 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>
+.one {
+  margin: 0 0 10px 0;
+}
+</style>

+ 104 - 0
src/views/platmanag/order/parts/search-1.vue

@@ -0,0 +1,104 @@
+<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="no">
+              <el-input v-model="form.no" placeholder="请输入订单号" size="small"></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col :span="7">
+            <el-form-item label="下单日期" prop="buy_time">
+              <el-date-picker
+                v-model="form.buy_time"
+                type="daterange"
+                range-separator="至"
+                start-placeholder="开始日期"
+                end-placeholder="结束日期"
+                value-format="yyyy-MM-dd"
+              >
+              </el-date-picker>
+            </el-form-item>
+          </el-col>
+          <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="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 }, shopList: { 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>

+ 1 - 1
src/views/selfShop/goods/spec.vue

@@ -123,7 +123,7 @@ export default {
     ...mapActions(['query', 'fetch', 'update', 'delete', 'create']),
     ...methodUtil,
     initAddData() {
-      const obj = { goods: this.goods, status: '0', can_group: '1', freight: '0' };
+      const obj = { goods: this.goods, status: '0', can_group: '1', freight: 0 };
       this.$set(this, 'form', obj);
     },
     async toSave({ data }) {