lrf402788946 3 роки тому
батько
коміт
392ed49eed

+ 14 - 1
src/components/filter-page-table.vue

@@ -280,7 +280,20 @@ export default {
     },
     filterSearch() {
       this.currentPage = 1;
-      this.$emit('query', { skip: 0, limit: this.limit, ...this.searchInfo });
+      const query = _.cloneDeep(this.searchInfo);
+      const dateType = this.fields.filter((f) => f.filter === 'date');
+      if (dateType.length > 0) {
+        for (const i of dateType) {
+          const { model } = i;
+          const data = query[model];
+          if (data && _.isArray(data) && data.length == 2) {
+            query[`${model}@start`] = data[0];
+            query[`${model}@end`] = data[1];
+          }
+          delete query[model];
+        }
+      }
+      this.$emit('query', { skip: 0, limit: this.limit, ...query });
     },
     rowClick(row, column, event) {
       this.$emit(`rowClick`, row);

+ 14 - 2
src/components/form.vue

@@ -11,6 +11,13 @@
       :style="styles"
       :inline="inline"
     >
+      <el-form-item v-if="back">
+        <el-row>
+          <el-col :span="24" style="text-align: right">
+            <el-button type="primary" size="mini" @click="toReturn">返回</el-button>
+          </el-col>
+        </el-row>
+      </el-form-item>
       <template v-for="(item, index) in fields">
         <template v-if="!loading">
           <el-form-item v-if="display(item)" :key="'form-field-' + index" :label="getField('label', item)" :prop="item.model" :required="item.required">
@@ -44,12 +51,12 @@
                   </template>
                   <template v-else-if="item.type === 'radio'">
                     <el-radio-group v-model="form[item.model]" size="mini" v-bind="item.options">
-                      <slot name="radios" v-bind="{ item, form, fieldChange }"></slot>
+                      <slot :name="item.model" v-bind="{ item, form, fieldChange }"></slot>
                     </el-radio-group>
                   </template>
                   <template v-else-if="item.type === 'checkbox'">
                     <el-checkbox-group v-model="form[item.model]" v-bind="item.options">
-                      <slot name="checkboxs" v-bind="{ item, form, fieldChange }"></slot>
+                      <slot :name="item.model" v-bind="{ item, form, fieldChange }"></slot>
                     </el-checkbox-group>
                   </template>
                   <template v-else-if="item.type === 'select'">
@@ -123,6 +130,7 @@ export default {
     submitText: { type: String, default: '保存' },
     inline: { type: Boolean, default: false },
     reset: { type: Boolean, default: true },
+    back: null,
   },
   components: {
     wangEditor,
@@ -197,6 +205,10 @@ export default {
       let { model, filterReturn } = item;
       if (filterReturn) this.$emit('filterReturn', { data, model });
     },
+    toReturn() {
+      if (_.isFunction(this.back)) eval(this.back)();
+      else this.$router.push(this.back);
+    },
   },
 };
 </script>

+ 1 - 1
src/components/wangEditor.vue

@@ -12,7 +12,7 @@ export default {
   props: {
     value: String,
     height: { type: Number, default: 300 }, //编辑区域高度
-    zIndex: { type: Number, default: 10000 }, //显示层级优先度
+    zIndex: { type: Number, default: 200 }, //显示层级优先度
     placeholder: { type: String }, //未输入时显示提示
     isFocus: { type: Boolean, default: false }, //是否自动焦点(自动切换到富文本上)
     url: { type: String }, //上传地址,如果没有下面的两个,或者用的时候缺对应项,也用这个,如果都没有,就提示有问题

+ 8 - 0
src/layout/admin/side/menu.vue

@@ -17,6 +17,14 @@
         <i class="el-icon-date"></i>
         <span slot="title">安排管理</span>
       </el-menu-item>
+      <el-menu-item index="/order">
+        <i class="el-icon-tickets"></i>
+        <span slot="title">查看订单</span>
+      </el-menu-item>
+      <el-menu-item index="/news">
+        <i class="el-icon-link"></i>
+        <span slot="title">新闻管理</span>
+      </el-menu-item>
     </el-menu>
   </div>
 </template>

+ 16 - 5
src/router/index.js

@@ -1,8 +1,7 @@
-import { _ } from 'core-js';
 import Vue from 'vue';
 import VueRouter from 'vue-router';
-import home from '../views/home.vue';
 import meatCheck from './meta-check';
+const _ = require('lodash');
 
 Vue.use(VueRouter);
 // check:需要检查的函数名
@@ -24,19 +23,31 @@ const routes = [
         path: '/site',
         name: 'site',
         meta: { title: '站点管理', parent: true },
-        component: () => import(/* webpackChunkName: "home" */ '../views/site/index.vue'),
+        component: () => import(/* webpackChunkName: "site" */ '../views/site/index.vue'),
       },
       {
         path: '/menu',
         name: 'menu',
         meta: { title: '菜单管理', parent: true },
-        component: () => import(/* webpackChunkName: "home" */ '../views/menu/index.vue'),
+        component: () => import(/* webpackChunkName: "menu" */ '../views/menu/index.vue'),
       },
       {
         path: '/arrange',
         name: 'arrange',
         meta: { title: '安排管理', parent: true },
-        component: () => import(/* webpackChunkName: "home" */ '../views/arrange/index.vue'),
+        component: () => import(/* webpackChunkName: "arrange" */ '../views/arrange/index.vue'),
+      },
+      {
+        path: '/order',
+        name: 'order',
+        meta: { title: '查看订餐', parent: true },
+        component: () => import(/* webpackChunkName: "order" */ '../views/order/index.vue'),
+      },
+      {
+        path: '/news',
+        name: 'news',
+        meta: { title: '新闻管理', parent: true },
+        component: () => import(/* webpackChunkName: "news" */ '../views/news/index.vue'),
       },
     ],
   },

+ 0 - 2
src/store/api/dining/arrange.js

@@ -1,8 +1,6 @@
 import Vue from 'vue';
 import Vuex from 'vuex';
 import _ from 'lodash';
-import { Message } from 'element-ui';
-const jwt = require('jsonwebtoken');
 Vue.use(Vuex);
 const api = {
   interface: `/api/st/dining/arrange`,

+ 43 - 0
src/store/api/dining/order.js

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

+ 42 - 0
src/store/api/system/news.js

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

+ 0 - 2
src/store/api/system/tenant.js

@@ -1,8 +1,6 @@
 import Vue from 'vue';
 import Vuex from 'vuex';
 import _ from 'lodash';
-import { Message } from 'element-ui';
-const jwt = require('jsonwebtoken');
 Vue.use(Vuex);
 const api = {
   interface: `/api/st/system/tenant`,

+ 3 - 1
src/store/index.js

@@ -4,8 +4,10 @@ import { fstate, opera, fgetter } from './setting/frame';
 import { ustate, uopera } from './setting/user';
 import admin from './api/system/admin';
 import tenant from './api/system/tenant';
+import news from './api/system/news';
 import menu from './api/dining/menu';
 import arrange from './api/dining/arrange';
+import order from './api/dining/order';
 Vue.use(Vuex);
 
 export default new Vuex.Store({
@@ -13,5 +15,5 @@ export default new Vuex.Store({
   mutations: { ...opera, ...uopera },
   actions: {},
   getters: { ...fgetter },
-  modules: { admin, tenant, menu, arrange },
+  modules: { admin, tenant, menu, arrange, order, news },
 });

+ 16 - 10
src/views/arrange/pc.vue

@@ -7,13 +7,13 @@
       <el-col :span="16">
         <el-tabs v-model="active" type="card">
           <el-tab-pane label="早餐" name="breakfast">
-            <mealTable v-model="form.arrange.breakfast" @save="toSave" />
+            <mealTable v-model="form.arrange.breakfast" @save="toSave" :loading="loading" />
           </el-tab-pane>
           <el-tab-pane label="午餐" name="lunch">
-            <mealTable v-model="form.arrange.lunch" @save="toSave" />
+            <mealTable v-model="form.arrange.lunch" @save="toSave" :loading="loading" />
           </el-tab-pane>
           <el-tab-pane label="晚餐" name="dinner">
-            <mealTable v-model="form.arrange.dinner" @save="toSave" />
+            <mealTable v-model="form.arrange.dinner" @save="toSave" :loading="loading" />
           </el-tab-pane>
         </el-tabs>
       </el-col>
@@ -34,6 +34,7 @@ export default {
   components: { mealTable },
   data: function () {
     return {
+      loading: false,
       date: new Date(),
       active: 'breakfast',
       form: {
@@ -57,13 +58,18 @@ export default {
       }
     },
     async toSave() {
-      const dup = _.cloneDeep(this.form);
-      if (!dup.date) dup.date = moment(this.date).format('YYYY-MM-DD');
-      let res;
-      if (dup._id) res = await this.update(dup);
-      else res = await this.create(dup);
-      if (this.$checkRes(res, '操作成功', res.errmsg || '操作失败')) {
-        this.getArrange(this.date);
+      try {
+        this.loading = true;
+        const dup = _.cloneDeep(this.form);
+        if (!dup.date) dup.date = moment(this.date).format('YYYY-MM-DD');
+        let res;
+        if (dup._id) res = await this.update(dup);
+        else res = await this.create(dup);
+        if (this.$checkRes(res, null, res.errmsg || '操作失败')) {
+          this.getArrange(this.date);
+        }
+      } finally {
+        this.loading = false;
       }
     },
     formInit() {

+ 12 - 2
src/views/arrange/pc/meal-table.vue

@@ -8,8 +8,17 @@
         <data-table :fields="fields" :opera="opera" :data="value" :usePage="false" operaWidth="auto" @delete="toDelete" />
       </el-col>
     </el-row>
-    <el-dialog title="参数编辑" :visible.sync="dialog" :width="width">
-      <data-table :fields="fields" :opera="operaDialog" :data="menuList" :usePage="false" operaWidth="auto" @select="toSelect" :height="height" />
+    <el-dialog title="添加本餐" :visible.sync="dialog" :width="width">
+      <data-table
+        :fields="fields"
+        :opera="operaDialog"
+        :data="menuList"
+        :usePage="false"
+        operaWidth="auto"
+        @select="toSelect"
+        :height="height"
+        v-loading="loading"
+      />
       <template #footer>
         <el-row>
           <el-col :span="24" style="text-align: center">
@@ -28,6 +37,7 @@ export default {
   name: 'meal-table',
   props: {
     value: { type: Array },
+    loading: { type: Boolean, default: false },
   },
   model: {
     prop: 'value',

+ 6 - 8
src/views/menu/index.vue

@@ -18,14 +18,9 @@
     </data-table>
 
     <div v-else>
-      <el-row type="flex" align="middle" justify="end">
-        <el-col :span="4">
-          <el-button type="primary" @click="view = 'list'" size="mini">返回</el-button>
-        </el-col>
-      </el-row>
       <el-row type="flex" align="middle" justify="space-around">
         <el-col :span="span">
-          <data-form :fields="formFields" v-model="form" @save="evalEdit" labelWidth="70px">
+          <data-form :fields="formFields" v-model="form" @save="evalEdit" labelWidth="70px" :back="toReturn">
             <template #params>
               <el-row>
                 <el-col :span="24" style="text-align: right">
@@ -44,7 +39,7 @@
               </el-row>
             </template>
             <template #img>
-              <e-upload v-model="form.img" url="/files/st/test/upload"></e-upload>
+              <e-upload v-model="form.img" url="/files/st/menu/upload"></e-upload>
             </template>
           </data-form>
         </el-col>
@@ -173,7 +168,7 @@ export default {
         center: true,
       })
         .then(async () => {
-          const res = await this.delete(data);
+          const res = await this.delete(data._id);
           if (this.$checkRes(res, '删除成功', res.errmsg || '删除失败')) {
             this.search();
           }
@@ -195,6 +190,9 @@ export default {
         img: [],
       };
     },
+    toReturn() {
+      this.view = 'list';
+    },
   },
   computed: {
     ...mapState(['user', 'isMobile']),

+ 64 - 0
src/views/news/detail.vue

@@ -0,0 +1,64 @@
+<template>
+  <div id="detail">
+    <data-form :fields="fields" v-model="data" @save="toSave" :labelWidth="labelWidth" :back="toReturn">
+      <template #type>
+        <el-radio label="0">国内新闻</el-radio>
+        <el-radio label="1">健康咨询</el-radio>
+      </template>
+      <template #img>
+        <e-upload v-model="data.img" url="/files/st/news/upload"></e-upload>
+      </template>
+    </data-form>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'detail',
+  props: {
+    data: { type: Object, default: () => {} },
+  },
+  model: {
+    prop: 'data',
+    event: 'change',
+  },
+  components: {},
+  data: function () {
+    return {
+      fields: [
+        { label: '标题', model: 'title' },
+        { label: '来源', model: 'origin' },
+        { label: '时间', model: 'create_time', type: 'date' },
+        { label: '类型', model: 'type', type: 'radio' },
+        { label: '图片', model: 'img', custom: true },
+        { label: '简介', model: 'brief' },
+        { label: '内容', model: 'content', type: 'editor' },
+      ],
+    };
+  },
+  created() {},
+  methods: {
+    toReturn() {
+      this.$emit('back');
+    },
+    toSave({ data }) {
+      this.$emit('save', data);
+    },
+  },
+  computed: {
+    ...mapState(['user', 'isMobile']),
+    pageTitle() {
+      return `${this.$route.meta.title}`;
+    },
+    labelWidth() {
+      return this.isMobile ? '40px' : '120px';
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 116 - 0
src/views/news/index.vue

@@ -0,0 +1,116 @@
+<template>
+  <div id="index">
+    <template v-if="view === 'list'">
+      <data-table :fields="fields" :opera="opera" :data="list" :total="total" @query="search" @edit="toEdit" @delete="toDelete" operaWidth="auto">
+        <template #btn>
+          <el-button type="primary" size="mini" @click="toAdd">添加</el-button>
+        </template>
+      </data-table>
+    </template>
+    <template v-else>
+      <detail v-model="form" @back="view = 'list'" @save="toSave" />
+    </template>
+  </div>
+</template>
+
+<script>
+import detail from './detail.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: news } = createNamespacedHelpers('news');
+export default {
+  name: 'index',
+  props: {},
+  components: { detail },
+  data: function () {
+    return {
+      view: 'list',
+      list: [],
+      total: 0,
+      fields: [
+        { label: '标题', model: 'title' },
+        { label: '来源', model: 'origin' },
+        { label: '时间', model: 'create_time' },
+        { label: '类型', model: 'type', format: (i) => (i === '0' ? '国内新闻' : '健康咨询') },
+      ],
+      opera: [
+        {
+          label: '编辑',
+          method: 'edit',
+        },
+        {
+          label: '删除',
+          type: 'danger',
+          method: 'delete',
+        },
+      ],
+      form: {
+        img: [],
+      },
+    };
+  },
+  created() {
+    this.search();
+  },
+  methods: {
+    ...news(['query', 'create', 'update', 'delete']),
+    async search({ skip = 0, limit = 10, ...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 toSave(data) {
+      let dup = _.cloneDeep(data);
+      let res;
+      if (dup._id) res = await this.update(dup);
+      else res = await this.create(dup);
+      if (this.$checkRes(res, '操作成功', res.errmsg || '操作失败')) {
+        this.search();
+        this.view = 'list';
+      }
+    },
+    async toDelete({ data }) {
+      this.$confirm('此操作将删除该数据, 是否继续?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning',
+        center: true,
+      })
+        .then(async () => {
+          const res = await this.delete(data._id);
+          if (this.$checkRes(res, '删除成功', res.errmsg || '删除失败')) {
+            this.search();
+          }
+        })
+        .catch(() => {});
+    },
+    async toAdd() {
+      this.formInit();
+      this.view = 'detail';
+    },
+    toEdit({ data }) {
+      console.log(data);
+      this.$set(this, 'form', _.cloneDeep(data));
+      this.view = 'detail';
+    },
+    formInit() {
+      const form = {
+        img: [],
+      };
+      this.$set(this, `form`, form);
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+    pageTitle() {
+      return `${this.$route.meta.title}`;
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 92 - 0
src/views/order/index.vue

@@ -0,0 +1,92 @@
+<template>
+  <div id="index">
+    <data-table :fields="fields" :opera="opera" :data="list" :total="total" @query="search" @detail="toDetail" operaWidth="auto" />
+    <el-dialog title="查看订餐" :visible.sync="dialog" :width="width">
+      <el-tabs v-model="active" type="card">
+        <el-tab-pane label="早餐" name="breakfast">
+          <meal :data="form.breakfast" />
+        </el-tab-pane>
+        <el-tab-pane label="午餐" name="lunch">
+          <meal :data="form.lunch" />
+        </el-tab-pane>
+        <el-tab-pane label="晚餐" name="dinner">
+          <meal :data="form.dinner" />
+        </el-tab-pane>
+      </el-tabs>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import meal from './meal.vue';
+import { mapState, createNamespacedHelpers } from 'vuex';
+const { mapActions: order } = createNamespacedHelpers('order');
+export default {
+  name: 'index',
+  props: {},
+  components: { meal },
+  data: function () {
+    return {
+      dialog: false,
+      active: 'breakfast',
+      list: [],
+      total: 0,
+      fields: [
+        { label: '日期', model: 'date', filter: 'date' },
+        { label: '早餐', model: 'breakfast', format: (i) => this.getMealStatus(i) },
+        { label: '午餐', model: 'lunch', format: (i) => this.getMealStatus(i) },
+        { label: '晚餐', model: 'dinner', format: (i) => this.getMealStatus(i) },
+      ],
+      opera: [
+        {
+          label: '详细',
+          method: 'detail',
+        },
+      ],
+      form: {},
+    };
+  },
+  created() {
+    this.search();
+  },
+  methods: {
+    ...order(['query']),
+    async search({ skip = 0, limit = 10, ...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);
+      }
+    },
+    getMealStatus(i) {
+      let res;
+      if (i.is_use === '0') res = '待使用';
+      else if (i.is_use === '1') res = '待评价';
+      else if (i.is_use === '2') res = '已完成';
+      else if (i.is_use === '3') res = '失效';
+      return res;
+    },
+    toDetail({ data }) {
+      this.$set(this, 'form', data);
+      this.dialog = true;
+    },
+    getList(type) {
+      return _.get(this.form, `${type}.list`, []);
+    },
+  },
+  computed: {
+    ...mapState(['user', 'isMobile']),
+    pageTitle() {
+      return `${this.$route.meta.title}`;
+    },
+    width() {
+      return this.isMobile ? '90%' : '30%';
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+};
+</script>
+
+<style lang="less" scoped></style>

+ 58 - 0
src/views/order/meal.vue

@@ -0,0 +1,58 @@
+<template>
+  <div id="meal">
+    <el-row v-if="data.list.length > 0">
+      <el-col :span="24"> 总卡路里:{{ data.reserve }}大卡 </el-col>
+      <el-col :span="24"> {{ getMealStatus(data) }} </el-col>
+      <el-col :span="24">
+        <data-table :fields="fields" :opera="[]" :data="data.list" :usePage="false" operaWidth="auto" :height="height" />
+      </el-col>
+    </el-row>
+    <el-row v-else>
+      <el-col :span="24">未订餐</el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'meal',
+  props: {
+    data: { type: Object, default: () => {} },
+  },
+  components: {},
+  data: function () {
+    return {
+      fields: [
+        { label: '菜品', model: 'name' },
+        { label: '卡路里(大卡)', model: 'reserve' },
+      ],
+    };
+  },
+  created() {},
+  methods: {
+    getMealStatus(i) {
+      let res;
+      if (i.is_use === '0') res = '待使用';
+      else if (i.is_use === '1') res = '待评价';
+      else if (i.is_use === '2') res = '已完成';
+      else if (i.is_use === '3') res = '失效';
+      return res;
+    },
+  },
+  computed: {
+    ...mapState(['user', 'isMobile']),
+    pageTitle() {
+      return `${this.$route.meta.title}`;
+    },
+    height() {
+      return this.isMobile ? '300px' : '500px';
+    },
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+};
+</script>
+
+<style lang="less" scoped></style>