asd123a20 3 年之前
父节点
当前提交
9bc16d088c

+ 1 - 6
admin-code/src/store/index.js

@@ -14,12 +14,7 @@ const api = {
 };
 
 const state = () => ({
-  dict: {
-    status: [
-      { code: '0', name: '正常' },
-      { code: '1', name: '注销' }
-    ]
-  },
+  dict: {},
   typeList: [],
   typeTotal: 0,
   codeList: [],

+ 2 - 2
admin-code/src/views/Home.vue

@@ -147,6 +147,7 @@ export default {
           res = await this.codeCreate(e);
           msg = '字典添加成功';
         }
+        this.filterQuery();
       } else {
         // 字典类别
         if (e._id) {
@@ -158,10 +159,9 @@ export default {
           res = await this.typeCreate(e);
           msg = '类别添加成功';
         }
+        this.treeQuery();
       }
       this.$resChange(res, msg);
-      this.treeQuery();
-      this.filterQuery();
       this.visibleSync = false;
     }
   }

+ 19 - 2
admin-content/src/store/index.js

@@ -5,12 +5,16 @@ const api = {
   contentsCreate: '/api/cms/contents/create',
   contentsUpdate: '/api/cms/contents/update',
   contentsDelete: '/api/cms/contents/delete',
-  contentsQuery: '/api/cms/contents/query'
+  contentsQuery: '/api/cms/contents/query',
+  contentsFetch: '/api/cms/contents/fetch',
+  columnQuery: '/api/cms/column/query'
 };
 Vue.use(Vuex);
 const state = () => ({
   Total: 0,
-  contentsList: []
+  contentsList: [],
+  columnList: [],
+  dict: {}
 });
 
 const actions = {
@@ -30,6 +34,15 @@ const actions = {
     const res = await $axios.get(api.contentsQuery, { ...filter, skip: paging.page, limit: paging.size });
     commit('contentsQuery', res);
     return res;
+  },
+  async contentsFetch ({ commit }, payload) {
+    const res = await $axios.get(api.contentsFetch, payload);
+    return res;
+  },
+  async columnQuery ({ commit }) {
+    const res = await $axios.get(api.columnQuery);
+    commit('columnQuery', res);
+    return res;
   }
 };
 
@@ -37,6 +50,10 @@ const mutations = {
   contentsQuery(state, payload) {
     state.contentsList = payload.data;
     state.Total = payload.total;
+  },
+  columnQuery(state, payload) {
+    state.columnList = payload.data;
+    state.dict.column = payload.data;
   }
 };
 

+ 104 - 12
admin-content/src/views/home.vue

@@ -6,12 +6,39 @@
         <el-button style="float: right; padding: 3px 0" type="text" @click="addcontents">添加文章</el-button>
       </div>
       <div class="main">
-        <filterList ref="filterList" :tableData="contentsList" :filed="filed" @edit="filtereEdit" @delete="filterDelete" @query="filterQuery" :total="Total"></filterList>
+        <filterList ref="filterList" :tableData="contents" :filed="filed" @edit="filtereEdit" @delete="filterDelete" @query="filterQuery" :total="Total">
+          <template v-slot:search="{ item, formInline }">
+            <el-select clearable v-if="item.name == 'bind'" v-model="formInline[item.name]" placeholder="请选择">
+              <el-option
+                v-for="i in columnList"
+                :key="i.value"
+                :label="i.name"
+                :value="i.code">
+              </el-option>
+            </el-select>
+          </template>
+        </filterList>
       </div>
     </el-card>
     <dialogAndDrawer :width="'35%'" :title="title" :visibleSync="visibleSync" v-if="visibleSync" @close="visibleSync = false">
       <template v-slot:windowMain>
-        <formData :filed="formfiled" :data="formdata" :rules="formrules" @save="formSave"></formData>
+        <formData ref="formData" :filed="formfiled" :data="formdata" :rules="formrules" @save="formSave" v-if="visibleSync">
+          <template v-slot:formItem="{ item, formdata }">
+            <!-- 缩略图 -->
+            <el-upload
+              v-if="item.name == 'thumbnail'"
+              class="avatar-uploader"
+              action="/api/files/avatar/upload"
+              :show-file-list="false"
+              :on-success="handleAvatarSuccess"
+              :before-upload="beforeAvatarUpload">
+              <img v-if="formdata[item.name] && formdata[item.name] !== ''" :src="formdata[item.name]" class="avatar">
+              <i v-else class="el-icon-plus avatar-uploader-icon"></i>
+            </el-upload>
+            <!-- 富文本 -->
+            <editoritem v-if="item.name == 'content'" @change="editChage" :value="formdata[item.name]"></editoritem>
+          </template>
+        </formData>
       </template>
     </dialogAndDrawer>
   </div>
@@ -20,37 +47,53 @@
 import filterList from '@components/filterList/index.vue';
 import dialogAndDrawer from '@components/dialogAndDrawer.vue';
 import formData from '@components/formData/index.vue';
+import editoritem from '@components/editoritem.vue';
 import { mapState, mapActions } from 'vuex';
 export default {
   components: {
     filterList,
     dialogAndDrawer,
-    formData
+    formData,
+    editoritem
   },
   data() {
     return {
       title: '',
       visibleSync: false,
       filed: [
-        { name: 'name', label: '名称', filter: true },
-        { name: 'code', label: '编码', filter: true }
+        { name: 'title', label: '标题', filter: true },
+        { name: 'bind', label: '绑定栏目', formater: 'slot', filter: true },
+        { name: 'visit', label: '访问量' }
       ],
       formdata: {},
       formfiled: [
-        { name: 'name', label: '名称' },
-        { name: 'code', label: '编码' }
+        { name: 'thumbnail', label: '缩略图', formater: 'slot' },
+        { name: 'title', label: '标题' },
+        { name: 'describe', label: '描述' },
+        { name: 'bind', label: '绑定栏目', formater: 'dict:column' },
+        { name: 'date', label: '时间', formater: 'date:datetime' },
+        { name: 'content', label: '内容', formater: 'slot' }
       ],
       formrules: {}
     };
   },
   computed: {
-    ...mapState(['contentsList', 'Total'])
+    ...mapState(['contentsList', 'Total', 'columnList']),
+    contents() {
+      this.contentsList.map(p => {
+        const findName = this.columnList.find(e => e.code == p.bind);
+        if (findName) p.bind = findName?.name;
+        return p;
+      });
+      return this.contentsList;
+    }
   },
   async mounted() {
     await this.filterQuery();
+    await this.columnQuery();
   },
   methods: {
-    ...mapActions(['contentsQuery', 'contentsCreate', 'contentsUpdate', 'contentsDelete', 'contentsQuery', 'queryBind', 'batchUnBind', 'batchBind']),
+    ...mapActions(['contentsQuery', 'contentsCreate', 'contentsUpdate', 'contentsDelete', 'contentsQuery', 'contentsFetch', 'columnQuery']),
     // 添加
     addcontents () {
       this.formdata = {};
@@ -58,8 +101,9 @@ export default {
       this.visibleSync = true;
     },
     // 修改
-    filtereEdit (e) {
-      this.formdata = e;
+    async filtereEdit (e) {
+      const res = await this.contentsFetch({ id: e._id });
+      this.formdata = res.data;
       this.title = '修改文章';
       this.visibleSync = true;
     },
@@ -70,7 +114,7 @@ export default {
       this.filterQuery();
     },
     // 查询
-    async filterQuery ({ filter = {}, paging = { page: 0, size: 10 } } = {}) {
+    async filterQuery ({ filter = {}, paging = { content: 0, size: 10 } } = {}) {
       await this.contentsQuery({ filter, paging });
     },
     // 表单保存
@@ -92,6 +136,27 @@ export default {
       this.$resChange(res, msg);
       this.filterQuery();
       this.visibleSync = false;
+    },
+    // 富文本改变
+    editChage (e) {
+      this.$refs.formData.setForm('content', e);
+    },
+    // 缩略图上传
+    handleAvatarSuccess(res, file) {
+      // this.imageUrl = URL.createObjectURL(file.raw);
+      this.$refs.formData.setForm('thumbnail', res.data.filePath);
+    },
+    beforeAvatarUpload(file) {
+      const isJPG = file.type === 'image/jpeg';
+      const isLt2M = file.size / 1024 / 1024 < 2;
+
+      if (!isJPG) {
+        this.$message.error('上传头像图片只能是 JPG 格式!');
+      }
+      if (!isLt2M) {
+        this.$message.error('上传头像图片大小不能超过 2MB!');
+      }
+      return isJPG && isLt2M;
     }
   }
 };
@@ -107,4 +172,31 @@ export default {
     }
   }
 }
+.el-dialog {
+  .avatar-uploader-icon {
+    font-size: 28px;
+    color: #8c939d;
+    width: 120px;
+    height: 120px;
+    line-height: 120px;
+    text-align: center;
+  }
+  .avatar {
+    width: 120px;
+    height: 120px;
+    display: block;
+  }
+}
+</style>
+<style>
+.el-upload {
+  border: 1px dashed #d9d9d9;
+  border-radius: 6px;
+  cursor: pointer;
+  position: relative;
+  overflow: hidden;
+}
+.el-upload:hover {
+  border-color: #409EFF;
+}
 </style>

+ 2 - 2
admin-frame/package-lock.json

@@ -7463,8 +7463,8 @@
     },
     "lodash": {
       "version": "4.17.21",
-      "resolved": "https://registry.npm.taobao.org/lodash/download/lodash-4.17.21.tgz",
-      "integrity": "sha1-Z5WRxWTDv/quhFTPCz3zcMPWkRw="
+      "resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz",
+      "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
     },
     "lodash.debounce": {
       "version": "4.0.8",

+ 1 - 0
admin-frame/package.json

@@ -11,6 +11,7 @@
     "axios": "^0.24.0",
     "core-js": "^3.6.5",
     "element-ui": "^2.15.6",
+    "lodash": "^4.17.21",
     "qiankun": "^2.6.0",
     "uuid": "^8.3.2",
     "vue": "^2.6.11",

+ 4 - 6
admin-frame/src/components/editoritem.vue

@@ -86,19 +86,17 @@ export default {
       // 自定义文件上传
       this.editor.config.customUploadImg = async function (resultFiles, insertImgFn) {
         // resultFiles 是 input 中选中的文件列表
-        // var data = new FormData();
+        var data = new FormData();
         const filesUpload = '/api/files/filestore/upload';
         data.append('file', resultFiles[0]);
-        data.append('app', 'filestore');
         const headers = {
           'Content-Type': 'multipart/form-data'
         };
-        const res = await $axios.post(filesUpload, { file: resultFiles[0] }, null, headers);
-        console.log(res, 'res');
+        const res = await $axios.post(filesUpload, data, null, headers);
         // insertImgFn 是获取图片 url 后,插入到编辑器的方法
-        // const url = res.data.path;
+        const url = res.data.filePath;
         // 上传图片,返回结果,将图片插入到编辑器中
-        // insertImgFn(url);
+        insertImgFn(url);
       };
       this.editor.config.onchange = (html) => {
         this.info_ = html; // 绑定当前逐渐地值

+ 2 - 2
admin-frame/src/components/filterList/index.vue

@@ -1,8 +1,8 @@
 <template>
   <div class="filter-box">
     <search v-if="filter" :filed="filterFiled" @query="searchQuery">
-      <template v-slot:search>
-        <slot name="search"></slot>
+      <template v-slot:search="{ item, formInline }">
+        <slot v-bind="{ item, formInline }" name="search"></slot>
       </template>
     </search>
     <tables

+ 6 - 2
admin-frame/src/components/filterList/search.vue

@@ -19,7 +19,7 @@
         format="yyyy 年 MM 月 dd 日"
       >
       </el-date-picker>
-      <slot v-if="item.formater == 'slot'" name="search"></slot>
+      <slot v-bind="{ item, formInline }" v-if="item.formater == 'slot'" name="search"></slot>
     </el-form-item>
     <!-- 按钮 -->
     <el-form-item>
@@ -30,6 +30,7 @@
 </template>
 
 <script>
+import _ from 'lodash';
 export default {
   name: 'filter-box',
   props: {
@@ -44,8 +45,11 @@ export default {
   },
   computed: {
     filterFiled() {
-      return this.filed.map(e => {
+      const fileds = _.cloneDeep(this.filed);
+      return fileds.map(e => {
         if (e.formater && e.formater.includes('dict')) {
+          console.log(e.formater.split(':')[1]);
+          console.log(this.$dict(e.formater.split(':')[1]));
           e.dict = this.$dict(e.formater.split(':')[1]);
           e.formater = 'dict';
         }

+ 3 - 3
admin-frame/src/components/filterList/调用实例.md

@@ -4,15 +4,15 @@ operation: [
 ## name = delete 时 会出现二次确认
     { name: 'delete', label: '删除', icon: 'el-icon-delete' }
 ],
-# 列表filed渲染
+# 列表filed渲染 formater为搜索使用
 filed: [
 ## 日期类型
     { label: '日期', name: 'date', icon: 'el-icon-time', filter: true, formater: 'date:datetime' },
 ## 普通输入类型
     { label: '名字', name: 'name', filter: true, placeholder: '输入名字' },
-## 选择类型
+<!-- ## 选择类型
     { label: '地址', name: 'address', filter: true, formater: 'dict:status' }
-],
+], -->
 # 列表显示数据
 tableData: [
     { date: '2016-05-02', name: '王小虎', address: '上海市普陀区金沙江路 1518 弄' },

+ 7 - 4
admin-frame/src/components/formData/index.vue

@@ -12,14 +12,15 @@
         clearable
         value-format="timestamp"
         v-if="item.formater == 'date'"
-        v-model="formInline[item.name]"
+        v-model="formdata[item.name]"
         :type="item.dateType"
-        :placeholder="item.placeholder || `选择${item.dateType == 'data' ? '日期' : '日期时间'}`"
-        format="yyyy 年 MM 月 dd 日"
+        :placeholder="item.placeholder || `选择${item.dateType == 'date' ? '日期' : '日期时间'}`"
       >
       </el-date-picker>
+      <!-- 插槽 -->
       <slot v-bind="{ item, formdata }" v-if="item.formater == 'slot'" name="formItem"></slot>
     </el-form-item>
+    <slot name="ext" v-bind="{ formdata }"></slot>
     <el-form-item>
       <el-button v-for="(item, index) in operation" :key="index" :type="item.name !== 'resetForm' ? 'primary' : ''" @click="formBtnClick(item.name, 'form')">{{ item.label }}</el-button>
     </el-form-item>
@@ -27,6 +28,7 @@
 </template>
 
 <script>
+import _ from 'lodash';
 export default {
   name: 'forms',
   props: {
@@ -50,7 +52,8 @@ export default {
   components: {},
   computed: {
     filterFiled() {
-      return this.filed.map(e => {
+      const fileds = _.cloneDeep(this.filed);
+      return fileds.map(e => {
         if (e.formater && e.formater.includes('dict')) {
           e.dict = this.$dict(e.formater.split(':')[1]);
           e.formater = 'dict';

+ 3 - 1
admin-frame/vue.config.js

@@ -23,7 +23,9 @@ module.exports = {
     proxy: {
       '/api/': {
         target: 'http://192.168.0.45:18090'
-        // target: 'http://127.0.0.1:18090'
+      },
+      '/upload/': {
+        target: 'http://192.168.0.45:9002'
       }
     }
   }

+ 70 - 5
admin-img-news/src/store/index.js

@@ -2,18 +2,49 @@ import Vue from 'vue';
 import Vuex from 'vuex';
 import $axios from '@lib/axios.js';
 const api = {
-  imgNewsCreate: '/api/cms/imgNews/create',
-  imgNewsUpdate: '/api/cms/imgNews/update',
-  imgNewsDelete: '/api/cms/imgNews/delete',
-  imgNewsQuery: '/api/cms/imgNews/query'
+  typeCreate: '/api/cms/imgtype/create',
+  typeUpdate: '/api/cms/imgtype/update',
+  typeDelete: '/api/cms/imgtype/delete',
+  typeQuery: '/api/cms/imgtype/query',
+  imgNewsCreate: '/api/cms/imgnews/create',
+  imgNewsUpdate: '/api/cms/imgnews/update',
+  imgNewsDelete: '/api/cms/imgnews/delete',
+  imgNewsQuery: '/api/cms/imgnews/query',
+  imgNewsFetch: '/api/cms/imgnews/fetch',
+  codeQuery: '/api/code/dictionary/query',
+  columnQuery: '/api/cms/column/query',
+  pagesQuery: '/api/cms/pages/query'
 };
 Vue.use(Vuex);
 const state = () => ({
   Total: 0,
-  imgNewsList: []
+  imgNewsList: [],
+  typeList: [],
+  typeTotal: 0,
+  dict: {},
+  columnList: [],
+  pagesList: []
 });
 
 const actions = {
+  async typeQuery({ commit }) {
+    const res = await $axios.get(api.typeQuery);
+    commit('typeQuery', res);
+    return res;
+  },
+  async typeCreate({ commit }, payload) {
+    const res = await $axios.post(api.typeCreate, payload);
+    return res;
+  },
+  async typeUpdate({ commit }, payload) {
+    payload = { ...payload, id: payload._id };
+    const res = await $axios.post(api.typeUpdate, payload);
+    return res;
+  },
+  async typeDelete({ commit }, { id }) {
+    const res = await $axios.delete(`${api.typeDelete}/${id}`);
+    return res;
+  },
   async imgNewsCreate ({ commit }, payload) {
     const res = await $axios.post(api.imgNewsCreate, payload);
     return res;
@@ -30,6 +61,25 @@ const actions = {
     const res = await $axios.get(api.imgNewsQuery, { ...filter, skip: paging.page, limit: paging.size });
     commit('imgNewsQuery', res);
     return res;
+  },
+  async imgNewsFetch ({ commit }, payload) {
+    const res = await $axios.get(api.imgNewsFetch, payload);
+    return res;
+  },
+  async codeQuery({ commit }) {
+    const res = await $axios.get(api.codeQuery, { parentCode: 'imgNewsType' });
+    commit('codeQuery', res);
+    return res;
+  },
+  async columnQuery ({ commit }) {
+    const res = await $axios.get(api.columnQuery);
+    commit('columnQuery', res);
+    return res;
+  },
+  async pagesQuery ({ commit }) {
+    const res = await $axios.get(api.pagesQuery);
+    commit('pagesQuery', res);
+    return res;
   }
 };
 
@@ -37,6 +87,21 @@ const mutations = {
   imgNewsQuery(state, payload) {
     state.imgNewsList = payload.data;
     state.Total = payload.total;
+  },
+  typeQuery(state, payload) {
+    state.typeList = payload.data;
+    state.dict.typeList = payload.data;
+    state.typeTotal = payload.total;
+  },
+  codeQuery(state, payload) {
+    state.dict.imgNewsType = payload.data;
+  },
+  columnQuery(state, payload) {
+    state.columnList = payload.data;
+    state.dict.column = payload.data;
+  },
+  pagesQuery(state, payload) {
+    state.pagesList = payload.data;
   }
 };
 

+ 195 - 26
admin-img-news/src/views/home.vue

@@ -1,5 +1,14 @@
 <template>
-  <div class="box">
+  <div class="imgnewshome">
+     <el-card class="box-card-left">
+      <div slot="header">
+        <span>新闻类别</span>
+        <el-tooltip effect="dark" content="添加类型" placement="top-start">
+          <el-button style="float: right; padding: 3px 0" icon="el-icon-plus" type="text" @click="treeTypeAdd"></el-button>
+        </el-tooltip>
+      </div>
+      <deepTree :operation="true" @edit="treeEdit" @remove="treeRemove" @nodeClick="treeClick" class="deepTree" :data="typeList"></deepTree>
+    </el-card>
     <el-card class="box-card">
       <div slot="header" class="clearfix">
         <span>图片新闻管理</span>
@@ -11,7 +20,41 @@
     </el-card>
     <dialogAndDrawer :width="'35%'" :title="title" :visibleSync="visibleSync" v-if="visibleSync" @close="visibleSync = false">
       <template v-slot:windowMain>
-        <formData :filed="formfiled" :data="formdata" :rules="formrules" @save="formSave"></formData>
+        <formData ref="formData" :filed="formfiled" :data="formdata" :rules="formrules" @save="formSave">
+          <template v-slot:formItem="{ item, formdata }">
+            <!-- 缩略图 -->
+            <el-upload
+              v-if="item.name == 'img'"
+              class="avatar-uploader"
+              action="/api/files/avatar/upload"
+              :show-file-list="false"
+              :on-success="handleAvatarSuccess"
+              :before-upload="beforeAvatarUpload">
+              <img v-if="formdata[item.name] && formdata[item.name] !== ''" :src="formdata[item.name]" class="avatar">
+              <i v-else class="el-icon-plus avatar-uploader-icon"></i>
+            </el-upload>
+          </template>
+          <template v-slot:ext="{ formdata }">
+            <!-- 地址 -->
+            <el-form-item v-if="formdata && formdata.type == '0'" label="地址">
+              <el-input v-model="formdata['url']" placeholder="请输入地址"></el-input>
+            </el-form-item>
+            <!-- 栏目 -->
+            <el-form-item v-if="formdata && formdata.type == '1'" label="栏目">
+              <el-select v-model="formdata['column']" placeholder="请选择栏目">
+                <el-option v-for="i in columnList" :key="i.code" :label="i.name" :value="i.code">
+                </el-option>
+              </el-select>
+            </el-form-item>
+            <!-- 单页 -->
+            <el-form-item v-if="formdata && formdata.type == '2'" label="单页">
+              <el-select v-model="formdata['pages']" placeholder="请选择单页">
+                <el-option v-for="i in pagesList" :key="i._id" :label="i.title" :value="i._id">
+                </el-option>
+              </el-select>
+            </el-form-item>
+          </template>
+        </formData>
       </template>
     </dialogAndDrawer>
   </div>
@@ -20,48 +63,74 @@
 import filterList from '@components/filterList/index.vue';
 import dialogAndDrawer from '@components/dialogAndDrawer.vue';
 import formData from '@components/formData/index.vue';
+import deepTree from '@components/deepTree.vue';
 import { mapState, mapActions } from 'vuex';
 export default {
   components: {
     filterList,
     dialogAndDrawer,
-    formData
+    formData,
+    deepTree
   },
   data() {
     return {
       title: '',
       visibleSync: false,
       filed: [
-        { name: 'name', label: '名称', filter: true },
-        { name: 'code', label: '编码', filter: true }
+        { name: 'title', label: '标题', filter: true },
+        { name: 'bind', label: '绑定类型编码' }
       ],
       formdata: {},
-      formfiled: [
-        { name: 'name', label: '名称' },
-        { name: 'code', label: '编码' }
-      ],
-      formrules: {}
+      formfiled: [],
+      formrules: {},
+      type: null
     };
   },
   computed: {
-    ...mapState(['imgNewsList', 'Total'])
+    ...mapState(['imgNewsList', 'Total', 'typeList', 'columnList', 'pagesList'])
   },
   async mounted() {
-    await this.filterQuery();
+    await this.typeQuery();
+    await this.codeQuery();
+    await this.columnQuery();
+    await this.pagesQuery();
   },
   methods: {
-    ...mapActions(['imgNewsQuery', 'imgNewsCreate', 'imgNewsUpdate', 'imgNewsDelete', 'imgNewsQuery', 'queryBind', 'batchUnBind', 'batchBind']),
+    ...mapActions(['typeQuery', 'typeCreate', 'typeUpdate', 'typeDelete', 'imgNewsQuery', 'imgNewsCreate', 'imgNewsUpdate', 'imgNewsDelete', 'imgNewsQuery', 'imgNewsFetch', 'codeQuery', 'columnQuery', 'pagesQuery']),
+    typeChage () {
+      if (this.type == null) {
+        // 类别
+        this.formfiled = [
+          { name: 'title', label: '名称', filter: true },
+          { name: 'type', label: '类型', filter: true }
+        ];
+      } else {
+        // 新闻
+        this.formfiled = [
+          { name: 'img', label: '缩略图', formater: 'slot' },
+          { name: 'title', label: '名称' },
+          { name: 'bind', label: '绑定类型', formater: 'dict:typeList' },
+          { name: 'type', label: '类型', formater: 'dict:imgNewsType' }
+        ];
+      }
+      this.visibleSync = true;
+    },
     // 添加
     addimgNews () {
+      if (this.type == null) {
+        this.$message.error('请先选择类型');
+        return;
+      }
       this.formdata = {};
       this.title = '添加图片新闻';
-      this.visibleSync = true;
+      this.typeChage();
     },
     // 修改
-    filtereEdit (e) {
-      this.formdata = e;
+    async filtereEdit (e) {
+      const res = await this.imgNewsFetch({ id: e._id });
+      this.formdata = res.data;
       this.title = '修改图片新闻';
-      this.visibleSync = true;
+      this.typeChage();
     },
     // 删除
     async filterDelete (e) {
@@ -71,8 +140,39 @@ export default {
     },
     // 查询
     async filterQuery ({ filter = {}, paging = { page: 0, size: 10 } } = {}) {
+      if (this.type == null) {
+        this.$message.error('请先选择类型');
+        return;
+      }
+      filter.bind = this.type;
       await this.imgNewsQuery({ filter, paging });
     },
+    // 添加
+    treeTypeAdd() {
+      this.type = null;
+      this.formdata = {};
+      this.title = '添加类别';
+      this.typeChage();
+    },
+    // 修改
+    treeEdit(e) {
+      this.type = null;
+      this.formdata = e;
+      this.title = '修改类别';
+      this.typeChage();
+    },
+    // 删除
+    async treeRemove(e) {
+      this.type = null;
+      const res = await this.typeDelete({ id: e?._id });
+      this.$resChange(res, '删除成功');
+      this.typeQuery();
+    },
+    // 选择
+    treeClick(e) {
+      this.type = e.data.code;
+      this.filterQuery();
+    },
     // 表单保存
     async formSave (e) {
       if (e.isRevise && e?.isRevise == false) {
@@ -81,30 +181,99 @@ export default {
       }
       this.$delete(e, 'isRevise');
       let res, msg;
-      // 修改
-      if (e._id) {
-        res = await this.imgNewsUpdate(e);
-        msg = '图片新闻修改成功';
+      // 图片新闻
+      if (this.type !== null) {
+        // 修改
+        if (e._id) {
+          res = await this.imgNewsUpdate(e);
+          msg = '图片新闻修改成功';
+        } else {
+          res = await this.imgNewsCreate(e);
+          msg = '图片新闻添加成功';
+        }
+        this.filterQuery();
       } else {
-        res = await this.imgNewsCreate(e);
-        msg = '图片新闻修改成功';
+        // 新闻类别
+        if (e._id) {
+          // 类别修改
+          res = await this.typeUpdate(e);
+          msg = '类别修改成功';
+        } else {
+          // 类别添加
+          res = await this.typeCreate(e);
+          msg = '类别添加成功';
+        }
+        this.typeQuery();
       }
       this.$resChange(res, msg);
-      this.filterQuery();
       this.visibleSync = false;
+    },
+    // 缩略图上传
+    handleAvatarSuccess(res, file) {
+      // this.imageUrl = URL.createObjectURL(file.raw);
+      this.$refs.formData.setForm('img', res.data.filePath);
+    },
+    beforeAvatarUpload(file) {
+      const isJPG = file.type === 'image/jpeg';
+      const isLt2M = file.size / 1024 / 1024 < 2;
+
+      if (!isJPG) {
+        this.$message.error('上传头像图片只能是 JPG 格式!');
+      }
+      if (!isLt2M) {
+        this.$message.error('上传头像图片大小不能超过 2MB!');
+      }
+      return isJPG && isLt2M;
     }
   }
 };
 </script>
-<style lang="scss" scoped>
-.box {
+<style lang="scss">
+.imgnewshome {
   width: 100%;
   height: 100%;
+  display: flex;
   .box-card {
+    width: 84%;
     height: 100%;
     .el-card__body {
       height: 100%;
     }
   }
+  .box-card-left {
+    width: 15%;
+    height: 100%;
+    .el-card__body {
+      height: 88%;
+      .deepTree {
+        width: 100%;
+        height: 100%;
+        overflow-y: auto;
+      }
+    }
+  }
+}
+.avatar-uploader-icon {
+  font-size: 28px;
+  color: #8c939d;
+  width: 120px;
+  height: 120px;
+  line-height: 120px !important;
+  text-align: center;
+}
+.avatar {
+  width: 120px;
+  height: 120px;
+  display: block;
+}
+.el-upload {
+  border: 1px dashed #d9d9d9;
+  border-radius: 6px;
+  cursor: pointer;
+  position: relative;
+  overflow: hidden;
+}
+.el-upload:hover {
+  border-color: #409EFF;
 }
 </style>

+ 33 - 2
admin-menu/src/store/index.js

@@ -5,12 +5,18 @@ const api = {
   menusCreate: '/api/cms/menus/create',
   menusUpdate: '/api/cms/menus/update',
   menusDelete: '/api/cms/menus/delete',
-  menusQuery: '/api/cms/menus/query'
+  menusQuery: '/api/cms/menus/query',
+  codeQuery: '/api/code/dictionary/query',
+  columnQuery: '/api/cms/column/query',
+  pagesQuery: '/api/cms/pages/query'
 };
 Vue.use(Vuex);
 const state = () => ({
   Total: 0,
-  menusList: []
+  menusList: [],
+  dict: {},
+  columnList: [],
+  pagesList: []
 });
 
 const actions = {
@@ -30,6 +36,21 @@ const actions = {
     const res = await $axios.get(api.menusQuery, { ...filter, skip: paging.page, limit: paging.size });
     commit('menusQuery', res);
     return res;
+  },
+  async codeQuery({ commit }) {
+    const res = await $axios.get(api.codeQuery, { parentCode: 'imgNewsType' });
+    commit('codeQuery', res);
+    return res;
+  },
+  async columnQuery ({ commit }) {
+    const res = await $axios.get(api.columnQuery);
+    commit('columnQuery', res);
+    return res;
+  },
+  async pagesQuery ({ commit }) {
+    const res = await $axios.get(api.pagesQuery);
+    commit('pagesQuery', res);
+    return res;
   }
 };
 
@@ -37,6 +58,16 @@ const mutations = {
   menusQuery(state, payload) {
     state.menusList = payload.data;
     state.Total = payload.total;
+  },
+  codeQuery(state, payload) {
+    state.dict.imgNewsType = payload.data;
+  },
+  columnQuery(state, payload) {
+    state.columnList = payload.data;
+    state.dict.column = payload.data;
+  },
+  pagesQuery(state, payload) {
+    state.pagesList = payload.data;
   }
 };
 

+ 38 - 10
admin-menu/src/views/home.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="box">
+  <div class="menushome">
     <el-card class="box-card">
       <div slot="header" class="clearfix">
         <span>菜单管理</span>
@@ -11,7 +11,28 @@
     </el-card>
     <dialogAndDrawer :width="'35%'" :title="title" :visibleSync="visibleSync" v-if="visibleSync" @close="visibleSync = false">
       <template v-slot:windowMain>
-        <formData :filed="formfiled" :data="formdata" :rules="formrules" @save="formSave"></formData>
+        <formData ref="formData" :filed="formfiled" :data="formdata" :rules="formrules" @save="formSave">
+          <template v-slot:ext="{ formdata }">
+            <!-- 地址 -->
+            <el-form-item v-if="formdata && formdata.type == '0'" label="地址">
+              <el-input v-model="formdata['url']" placeholder="请输入地址"></el-input>
+            </el-form-item>
+            <!-- 栏目 -->
+            <el-form-item v-if="formdata && formdata.type == '1'" label="栏目">
+              <el-select v-model="formdata['column']" placeholder="请选择栏目">
+                <el-option v-for="i in columnList" :key="i.code" :label="i.name" :value="i.code">
+                </el-option>
+              </el-select>
+            </el-form-item>
+            <!-- 单页 -->
+            <el-form-item v-if="formdata && formdata.type == '2'" label="单页">
+              <el-select v-model="formdata['pages']" placeholder="请选择单页">
+                <el-option v-for="i in pagesList" :key="i._id" :label="i.title" :value="i._id">
+                </el-option>
+              </el-select>
+            </el-form-item>
+          </template>
+        </formData>
       </template>
     </dialogAndDrawer>
   </div>
@@ -38,19 +59,24 @@ export default {
       formdata: {},
       formfiled: [
         { name: 'name', label: '名称' },
-        { name: 'code', label: '编码' }
+        { name: 'code', label: '编码' },
+        { name: 'date', label: '时间', formater: 'date:datetime' },
+        { name: 'type', label: '类型', formater: 'dict:imgNewsType' }
       ],
       formrules: {}
     };
   },
   computed: {
-    ...mapState(['menusList', 'Total'])
+    ...mapState(['menusList', 'Total', 'typeList', 'columnList', 'pagesList'])
   },
   async mounted() {
     await this.filterQuery();
+    await this.codeQuery();
+    await this.columnQuery();
+    await this.pagesQuery();
   },
   methods: {
-    ...mapActions(['menusQuery', 'menusCreate', 'menusUpdate', 'menusDelete', 'menusQuery', 'queryBind', 'batchUnBind', 'batchBind']),
+    ...mapActions(['menusQuery', 'menusCreate', 'menusUpdate', 'menusDelete', 'menusQuery', 'codeQuery', 'columnQuery', 'pagesQuery']),
     // 添加
     addmenus () {
       this.formdata = {};
@@ -58,7 +84,7 @@ export default {
       this.visibleSync = true;
     },
     // 修改
-    filtereEdit (e) {
+    async filtereEdit (e) {
       this.formdata = e;
       this.title = '修改菜单';
       this.visibleSync = true;
@@ -87,20 +113,22 @@ export default {
         msg = '菜单修改成功';
       } else {
         res = await this.menusCreate(e);
-        msg = '菜单修改成功';
+        msg = '菜单添加成功';
       }
-      this.$resChange(res, msg);
       this.filterQuery();
+      this.$resChange(res, msg);
       this.visibleSync = false;
     }
   }
 };
 </script>
-<style lang="scss" scoped>
-.box {
+<style lang="scss">
+.menushome {
   width: 100%;
   height: 100%;
+  display: flex;
   .box-card {
+    width: 100%;
     height: 100%;
     .el-card__body {
       height: 100%;

+ 3 - 0
admin-page/vue.config.js

@@ -11,6 +11,9 @@ module.exports = {
       '/api/': {
         target: 'http://192.168.0.45:18090'
         // target: 'http://127.0.0.1:18090'
+      },
+      '/upload/': {
+        target: 'http://192.168.0.45:9002'
       }
     }
   },

+ 4 - 4
admin-toconfig/src/store/index.js

@@ -2,10 +2,10 @@ import Vue from 'vue';
 import Vuex from 'vuex';
 import $axios from '@lib/axios.js';
 const api = {
-  toConfigCreate: '/api/cms/toConfig/create',
-  toConfigUpdate: '/api/cms/toConfig/update',
-  toConfigDelete: '/api/cms/toConfig/delete',
-  toConfigQuery: '/api/cms/toConfig/query'
+  toConfigCreate: '/api/cms/toconfig/create',
+  toConfigUpdate: '/api/cms/toconfig/update',
+  toConfigDelete: '/api/cms/toconfig/delete',
+  toConfigQuery: '/api/cms/toconfig/query'
 };
 Vue.use(Vuex);
 const state = () => ({

+ 3 - 2
admin-toconfig/src/views/home.vue

@@ -38,7 +38,8 @@ export default {
       formdata: {},
       formfiled: [
         { name: 'name', label: '名称' },
-        { name: 'code', label: '编码' }
+        { name: 'code', label: '编码' },
+        { name: 'value', label: '内容' }
       ],
       formrules: {}
     };
@@ -50,7 +51,7 @@ export default {
     await this.filterQuery();
   },
   methods: {
-    ...mapActions(['toConfigQuery', 'toConfigCreate', 'toConfigUpdate', 'toConfigDelete', 'toConfigQuery', 'queryBind', 'batchUnBind', 'batchBind']),
+    ...mapActions(['toConfigQuery', 'toConfigCreate', 'toConfigUpdate', 'toConfigDelete', 'toConfigQuery']),
     // 添加
     addtoConfig () {
       this.formdata = {};