Bladeren bron

feat: #引入预览图片,初步完善对接接口(banner、问题反馈页面)

loki 3 jaren geleden
bovenliggende
commit
88f8b2ab12

+ 1 - 0
package.json

@@ -22,6 +22,7 @@
     "nprogress": "0.2.0",
     "path-to-regexp": "2.4.0",
     "qs": "^6.10.1",
+    "v-viewer": "^1.6.3",
     "vue": "2.6.10",
     "vue-router": "3.0.6",
     "vuex": "3.1.0"

+ 1 - 1
src/App.vue

@@ -7,5 +7,5 @@
 <script>
 export default {
   name: 'App'
-}
+};
 </script>

+ 10 - 0
src/api/base/banner.js

@@ -0,0 +1,10 @@
+import api from '@/utils/request';
+
+export const getList = params =>
+	api.post(`/yxl-back-end/admin/banner/page`, params);
+export const getItem = ({ id, params }) =>
+	api.get(`/yxl-back-end/framework/help/content/${id}`, params);
+export const saveItem = params =>
+	api.post(`/yxl-back-end/framework/help/content/save`, params);
+export const delItem = ({ id, params }) =>
+	api.del(`/yxl-back-end/framework/help/content/${id}`, params);

+ 4 - 0
src/api/base/problemFeedback.js

@@ -0,0 +1,4 @@
+import api from '@/utils/request';
+
+export const getList = params =>
+	api.post(`/yxl-back-end/framework/feedback/page`, params);

+ 79 - 0
src/components/AdvanceViewImage.vue

@@ -0,0 +1,79 @@
+<template>
+  <viewer
+    :images="items"
+    :options="options"
+    class="viewer"
+    ref="viewer"
+    @inited="inited"
+    style="display: none"
+  >
+    <template slot-scope="scope">
+      <img
+        v-for="(item, i) in scope.images"
+        :src="item.src"
+        :key="i"
+        :alt="item.alt"
+      />
+      {{ scope.options }}
+    </template>
+  </viewer>
+</template>
+
+<script>
+export default {
+  name: 'AdvanceViewImage',
+  props: {
+    items: {
+      type: Array,
+      default: () => []
+    },
+    index: {
+      type: Number,
+      default: 0
+    }
+  },
+  data() {
+    return {
+      value: false,
+      options: {
+        zIndex: 9999,
+        hidden: () => {
+          this.$emit('input', false);
+        }
+      }
+    };
+  },
+  mounted() {
+    this.value = true;
+  },
+  methods: {
+    inited(viewer) {
+      this.$viewer = viewer;
+    },
+    showById(id, list) {
+      let index = 0;
+      this.items.forEach((x, i) => {
+        if (x.id === id) {
+          index = i;
+        }
+      });
+      this.$viewer.view(index);
+    },
+
+    showByIndex(index) {
+      this.$viewer.view(index);
+    }
+  },
+  watch: {
+    value: {
+      handler(val) {
+        if (val) {
+          this.showByIndex(this.index);
+        } else {
+          this.$emit('cancel');
+        }
+      }
+    }
+  }
+};
+</script>

+ 4 - 3
src/components/BaseTable.vue

@@ -39,12 +39,13 @@
                 <el-tag
                   size="medium"
                   :type="column.fetchTagType(scope.row[column.key]) || ''"
-                  >{{
+                >
+                  {{
                     typeof column.tagName === 'function'
                       ? column.tagName(scope.row)
                       : scope.row[column.key]
-                  }}</el-tag
-                >
+                  }}
+                </el-tag>
               </span>
               <span v-else>{{ scope.row[column.key] || '-' }}</span>
             </template>

+ 28 - 0
src/components/BaseTooltip.vue

@@ -0,0 +1,28 @@
+<template>
+  <el-tooltip :content="txt" placement="top">
+    <span>{{ omitTxt }}</span>
+  </el-tooltip>
+</template>
+
+<script>
+export default {
+  name: 'BaseTooltip',
+  props: {
+    txt: {
+      type: String,
+      default: ''
+    }
+  },
+
+  computed: {
+    omitTxt() {
+      let str = this.txt;
+      return str.length > 20 ? str.slice(0, 20) : str;
+    }
+  },
+
+  methods: {}
+};
+</script>
+
+<style lang="scss" scoped></style>

+ 4 - 0
src/components/index.js

@@ -1,12 +1,16 @@
 import Vue from 'vue';
+import AdvanceViewImage from './AdvanceViewImage.vue';
 import BaseBtn from './BaseBtn.vue';
 import BaseTable from './BaseTable.vue';
+import BaseTooltip from './BaseTooltip.vue';
 import Breadcrumb from './Breadcrumb.vue';
 import Hamburger from './Hamburger.vue';
 import SvgIcon from './SvgIcon.vue';
 
+Vue.component('AdvanceViewImage', AdvanceViewImage);
 Vue.component('BaseBtn', BaseBtn);
 Vue.component('BaseTable', BaseTable);
+Vue.component('BaseTooltip', BaseTooltip);
 Vue.component('Breadcrumb', Breadcrumb);
 Vue.component('Hamburger', Hamburger);
 Vue.component('SvgIcon', SvgIcon);

+ 1 - 0
src/main.js

@@ -19,6 +19,7 @@ import './components';
 import './containers';
 
 import 'utils/dialog-helper';
+import '@/plugins/viewerjs';
 
 import message from '@/utils/message';
 

+ 4 - 0
src/plugins/viewerjs.js

@@ -0,0 +1,4 @@
+import Vue from 'vue';
+import Viewer from 'v-viewer';
+import 'viewerjs/dist/viewer.css';
+Vue.use(Viewer);

+ 16 - 0
src/utils/dialog-helper.js

@@ -1,7 +1,9 @@
 import Vue from 'vue';
 import store from 'store';
+import AdvanceViewImage from 'components/AdvanceViewImage.vue';
 import IssueTypeItem from 'views/helpInfo/issueType/modal/ItemModal.vue';
 import InformationItem from 'views/helpInfo/information/modal/ItemModal.vue';
+import BannerItem from 'views/baseManagement/bannerManagement/modal/ItemModal.vue';
 
 const modal = (Component, props) => {
   let _component = null;
@@ -24,6 +26,13 @@ const modal = (Component, props) => {
   document.body.appendChild(_component.$el);
 };
 
+let AdvanceViewImageModal = data => {
+  modal(AdvanceViewImage, data);
+};
+Vue.prototype.$AdvanceViewImageModal = params => {
+  AdvanceViewImageModal(params);
+};
+
 let IssueTypeItemModal = data => {
   modal(IssueTypeItem, data);
 };
@@ -37,3 +46,10 @@ let InformationItemModal = data => {
 Vue.prototype.$InformationItemModal = params => {
   InformationItemModal(params);
 };
+
+let BannerItemModal = data => {
+  modal(BannerItem, data);
+};
+Vue.prototype.$BannerItemModal = params => {
+  BannerItemModal(params);
+};

+ 1 - 1
src/utils/request.js

@@ -27,7 +27,7 @@ axios.interceptors.request.use(
       // let each request carry token
       // ['X-Token'] is a custom headers key
       // please modify it according to the actual situation
-      config.headers['X-Token'] = getToken();
+      config.headers['token'] = getToken();
     }
     return config;
   },

+ 87 - 11
src/views/baseManagement/bannerManagement/index.vue

@@ -3,7 +3,7 @@
     <toolbar @onSearch="filterData" />
 
     <div class="m-10 bg-w p-20 br-10">
-      <el-button type="primary" icon="el-icon-plus" @click="handleSubmit"
+      <el-button type="primary" icon="el-icon-plus" @click="handleAdd"
         >新增</el-button
       >
       <base-table
@@ -19,6 +19,7 @@
 <script>
 import toolbar from './toolbar';
 import mxFilterList from '@/mixins/filterList';
+import { getList } from '@/api/base/banner';
 
 export default {
   name: 'BannerManagement',
@@ -27,7 +28,7 @@ export default {
 
   mixins: [
     mxFilterList({
-      // fetchList: iGetList // 在下方data再声明一个 fetchList: iGetList 同等效果
+      fetchList: getList // 在下方data再声明一个 fetchList: iGetList 同等效果
     })
   ],
 
@@ -40,43 +41,118 @@ export default {
           width: '60'
         },
         {
-          key: 'photo',
+          key: 'imgUrl',
           name: '图片',
-          width: '240'
+          width: '240',
+          render: (h, { row }) =>
+            h('image', {
+              style: {
+                width: '160px',
+                height: '90px'
+              },
+              attrs: {
+                src: row.imgUrl
+              },
+              on: {
+                click: () =>
+                  this.$AdvanceViewImageModal({
+                    items: [{ src: row.imgUrl }]
+                  })
+              }
+            })
         },
         {
-          key: 'region',
+          key: 'type',
           name: '位置',
           minWidth: '120'
         },
         {
-          key: 'region',
+          key: 'name',
           name: '标题',
           minWidth: '180'
         },
         {
-          key: 'region',
+          key: 'link',
           name: '链接',
           minWidth: '240',
           showOverflowTooltip: true
         },
         {
-          key: 'region',
+          key: 'sort',
           name: '排序',
           width: '60'
         },
         {
-          key: 'region',
+          key: 'isShow',
           name: '状态',
-          width: '80'
+          width: '80',
+          type: 'tag',
+          fetchTagType: val => (val ? 'success' : 'info'),
+          tagName: row => (row.isShow ? '显示' : '隐藏')
         },
         {
           key: 'action',
           name: '操作',
-          width: '120'
+          width: '120',
+          render: (h, { row }) => {
+            const action = [];
+            action.push(
+              h(
+                'el-button',
+                {
+                  props: {
+                    type: 'text'
+                  },
+                  on: {
+                    click: () =>
+                      this.$BannerItemModal({
+                        id: row.id,
+                        parentId: row.parentId
+                      })
+                  }
+                },
+                '编辑'
+              )
+            );
+            action.push(
+              h(
+                'BaseBtn',
+                {
+                  props: {
+                    popip: true,
+                    txt: '删除',
+                    type: 'text'
+                  },
+                  class: 'ml-10',
+                  on: {
+                    ok: () => this.handleDelItem(row)
+                  }
+                },
+                '删除'
+              )
+            );
+
+            return h('div', action);
+          }
         }
       ]
     };
+  },
+
+  methods: {
+    handleAdd() {
+      this.$BannerItemModal();
+    },
+    async handleDelItem(item) {
+      const { success, msg } = await delItem({
+        id: item.id
+      });
+      if (success) {
+        this.$success('删除成功!');
+      } else {
+        this.$error(msg);
+      }
+    }
   }
 };
 </script>

+ 150 - 0
src/views/baseManagement/bannerManagement/modal/ItemModal.vue

@@ -0,0 +1,150 @@
+<template>
+  <el-dialog
+    :title="title"
+    :visible.sync="modal"
+    width="500px"
+    :close-on-click-modal="false"
+    @close="
+      res => {
+        $emit('cancel');
+      }
+    "
+  >
+    <el-form ref="form" :model="form" :rules="rules" label-width="100px">
+      <!-- TODO 补充图片上传 -->
+      <el-form-item label="位置" prop="type">
+        <el-select
+          v-model="form.type"
+          :clearable="true"
+          placeholder="请选择所属位置"
+        >
+          <el-option
+            v-for="item in typeOptions"
+            :key="item.value"
+            :label="item.label"
+            :value="item.value"
+          >
+          </el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="标题" prop="name">
+        <el-input v-model="form.name"></el-input>
+      </el-form-item>
+      <el-form-item label="链接" prop="link">
+        <el-input v-model="form.link"></el-input>
+      </el-form-item>
+      <el-form-item label="状态">
+        <el-radio-group v-model="form.isShow" prop="isShow">
+          <el-radio :label="true">显示</el-radio>
+          <el-radio :label="false">隐藏</el-radio>
+        </el-radio-group>
+      </el-form-item>
+      <el-form-item label="排序" prop="sort">
+        <el-input-number
+          v-model="form.sort"
+          :min="1"
+          :max="9999"
+          label="序号"
+        ></el-input-number>
+      </el-form-item>
+    </el-form>
+    <span slot="footer" class="dialog-footer">
+      <el-button @click="modal = false">取消</el-button>
+      <el-button type="primary" @click="handleConfirm">确定</el-button>
+    </span>
+  </el-dialog>
+</template>
+
+<script>
+import { getItem, saveItem } from '@/api/base/banner';
+
+export default {
+  name: 'BannerItemModal',
+
+  props: {
+    id: {
+      type: String,
+      default: ''
+    },
+    parentId: {
+      type: String,
+      default: '-1'
+    }
+  },
+
+  data() {
+    return {
+      modal: true,
+
+      form: {
+        type: null,
+        name: '',
+        link: '',
+        isShow: false,
+        sort: 1
+      },
+      rules: {
+        name: [
+          { required: true, message: '请选择所属位置', trigger: 'change' }
+        ],
+        name: [{ required: true, message: '请输入标题', trigger: 'change' }],
+        link: [{ required: true, message: '请输入链接地址', trigger: 'change' }]
+      },
+
+      typeOptions: []
+    };
+  },
+
+  computed: {
+    title() {
+      if (this.id) {
+        return '编辑Banner';
+      } else {
+        return '新增Banner';
+      }
+    }
+  },
+
+  watch: {
+    id: {
+      handler(id) {
+        id && this.loadData();
+      },
+      immediate: true
+    }
+  },
+
+  mounted() {},
+
+  methods: {
+    async loadData() {
+      const { success, data, msg } = await getItem({
+        id: this.id
+      });
+      if (success) {
+        this.form = data;
+      } else {
+        this.$error(msg);
+      }
+    },
+
+    handleConfirm() {
+      this.$refs.form.validate(async valid => {
+        if (valid) {
+          const params = Object.assign({}, this.form);
+          if (this.id) params.id = this.id;
+          const { success, msg } = await saveItem(params);
+          if (success) {
+            this.$success('保存成功!');
+            this.modal = false;
+          } else {
+            this.$error(msg);
+          }
+        }
+      });
+    }
+  }
+};
+</script>
+
+<style lang="scss" scoped></style>

+ 67 - 6
src/views/baseManagement/problemFeedbackManagement/index.vue

@@ -15,6 +15,7 @@
 <script>
 import toolbar from './toolbar';
 import mxFilterList from '@/mixins/filterList';
+import { getList } from '@/api/base/problemFeedback';
 
 export default {
   name: 'ProblemFeedbackManagement',
@@ -31,27 +32,87 @@ export default {
     return {
       columns: [
         {
-          key: 'photo',
+          key: 'accountNickname',
           name: '用户名称',
           width: '160'
         },
         {
-          key: 'region',
+          key: 'phonenumber',
           name: '手机号',
           width: '180'
         },
         {
-          key: 'region',
+          key: 'content',
           name: '反馈内容',
-          minWidth: '120'
+          minWidth: '120',
+          render: (h, { row }) => {
+            let str = row.content;
+            // return h(
+            //   'el-tooltip',
+            //   {
+            //     props: {
+            //       content: str,
+            //       placement: 'top'
+            //     }
+            //   },
+            //   'dadad1'
+            //   // h('span', str.length > 20 ? str.slice(0, 20) : str)
+            // );
+            return h('BaseTooltip', {
+              props: {
+                txt: str
+              }
+            });
+          }
+        },
+        {
+          key: 'photo',
+          name: '反馈图片',
+          width: '100',
+          render: (h, { row }) => {
+            const list = row.imgUrl.map(x => ({
+              src: x
+            }));
+            if (list.length > 0) {
+              return h('image', {
+                style: {
+                  width: '90px',
+                  height: '90px'
+                },
+                attrs: {
+                  src: list[0].url
+                },
+                on: {
+                  click: () =>
+                    this.$AdvanceViewImageModal({
+                      items: list
+                    })
+                }
+              });
+            } else {
+              return h('span', '-');
+            }
+          }
         },
         {
-          key: 'region',
+          key: 'createAt',
           name: '反馈时间',
-          width: '180'
+          minWidth: '100'
         }
       ]
     };
+  },
+
+  mounted() {
+    setTimeout(() => {
+      this.items = [
+        {
+          accountNickname: 'loic',
+          phonenumber: '110',
+          content: 'dadadabkwadl冬不拉我的本垒打我看了金额逻辑框架出来就安慰'
+        }
+      ];
+    }, 1000);
   }
 };
 </script>

+ 1 - 1
src/views/helpInfo/information/modal/ItemModal.vue

@@ -31,7 +31,7 @@
         <el-input-number
           v-model="form.sort"
           :min="1"
-          :max="10"
+          :max="9999"
           label="序号"
         ></el-input-number>
       </el-form-item>

+ 1 - 6
src/views/helpInfo/issueType/modal/ItemModal.vue

@@ -15,11 +15,6 @@
         <el-input v-model="form.name"></el-input>
       </el-form-item>
       <el-form-item label="状态">
-        <!-- <el-switch
-          v-model="form.isShow"
-          active-text="显示"
-          inactive-text="隐藏"
-        /> -->
         <el-radio-group v-model="form.isShow" prop="isShow">
           <el-radio :label="true">显示</el-radio>
           <el-radio :label="false">隐藏</el-radio>
@@ -29,7 +24,7 @@
         <el-input-number
           v-model="form.sort"
           :min="1"
-          :max="10"
+          :max="9999"
           label="序号"
         ></el-input-number>
       </el-form-item>

+ 1 - 0
src/views/login/index.vue

@@ -136,6 +136,7 @@ export default {
       immediate: true
     }
   },
+
   methods: {
     handleLogin() {
       this.$refs.loginForm.validate(valid => {