7 次代码提交 fe06e722cf ... f6d178071c

作者 SHA1 备注 提交日期
  mnisting f6d178071c feat: 资讯管理-轮播图管理页面初始化及接口联调 8 月之前
  mnisting f5aed5146f feat: 资讯信息页面初始化及接口联调 8 月之前
  mnisting 563b019bad feat: 资讯分类页面优化 8 月之前
  mnisting 008895b2f0 feat: 远程搜索组件优化 8 月之前
  mnisting 6803b055c0 feat: 项目标题配置修改 8 月之前
  mnisting 6fce5d23d9 feat: 新增触底请求接口加载下一页的自定义指令,封装多页码几口的下拉框远程搜索组件 8 月之前
  mnisting e94fe5bb22 feat: 优化图片上传公共组件 8 月之前

+ 1 - 1
.env.development

@@ -1,5 +1,5 @@
 # 页面标题
 # 页面标题
-VUE_APP_TITLE = 阿卜小程序管理系统
+VUE_APP_TITLE = 泰兴反诈管理系统
 
 
 # 开发环境配置
 # 开发环境配置
 ENV = 'development'
 ENV = 'development'

+ 1 - 1
.env.production

@@ -1,5 +1,5 @@
 # 页面标题
 # 页面标题
-VUE_APP_TITLE = 阿卜小程序管理系统
+VUE_APP_TITLE = 泰兴反诈管理系统
 
 
 # 生产环境配置
 # 生产环境配置
 ENV = 'production'
 ENV = 'production'

+ 1 - 1
.env.staging

@@ -1,5 +1,5 @@
 # 页面标题
 # 页面标题
-VUE_APP_TITLE = 阿卜小程序管理系统
+VUE_APP_TITLE = 泰兴反诈管理系统
 
 
 NODE_ENV = production
 NODE_ENV = production
 
 

+ 1 - 1
package.json

@@ -1,7 +1,7 @@
 {
 {
   "name": "ruoyi",
   "name": "ruoyi",
   "version": "3.8.2",
   "version": "3.8.2",
-  "description": "阿卜小程序管理系统",
+  "description": "泰兴反诈管理系统",
   "author": "若依",
   "author": "若依",
   "license": "MIT",
   "license": "MIT",
   "scripts": {
   "scripts": {

+ 44 - 0
src/api/infoManage/carouselManage/index.js

@@ -0,0 +1,44 @@
+import request from "@/utils/request";
+
+// 查询列表
+export function getList(query) {
+  return request({
+    url: "/banner/info/list",
+    method: "get",
+    params: query,
+  });
+}
+
+// 查询详情
+export function getDetail(id) {
+  return request({
+    url: `/banner/info/${id}`,
+    method: "get",
+  });
+}
+
+// 新增
+export function add(data) {
+  return request({
+    url: "/banner/info",
+    method: "post",
+    data,
+  });
+}
+
+// 修改
+export function update(data) {
+  return request({
+    url: "/banner/info",
+    method: "put",
+    data,
+  });
+}
+
+// 删除
+export function del(ids) {
+  return request({
+    url: `/banner/info/${ids}`,
+    method: "delete",
+  });
+}

+ 44 - 0
src/api/infoManage/news/index.js

@@ -0,0 +1,44 @@
+import request from "@/utils/request";
+
+// 查询列表
+export function getList(query) {
+  return request({
+    url: "/info/infoContent/list",
+    method: "get",
+    params: query,
+  });
+}
+
+// 查询详情
+export function getDetail(id) {
+  return request({
+    url: `/info/infoContent/${id}`,
+    method: "get",
+  });
+}
+
+// 新增
+export function add(data) {
+  return request({
+    url: "/info/infoContent",
+    method: "post",
+    data,
+  });
+}
+
+// 修改
+export function update(data) {
+  return request({
+    url: "/info/infoContent",
+    method: "put",
+    data,
+  });
+}
+
+// 删除
+export function del(ids) {
+  return request({
+    url: `/info/infoContent/${ids}`,
+    method: "delete",
+  });
+}

+ 10 - 0
src/api/public.js

@@ -0,0 +1,10 @@
+import request from "@/utils/request";
+
+// 获取路由
+export const getData = (url, query) => {
+  return request({
+    url,
+    method: "get",
+    params: query,
+  });
+};

+ 39 - 27
src/components/ImageUpload/index.vue

@@ -2,6 +2,7 @@
   <div class="component-upload-image">
   <div class="component-upload-image">
     <el-upload
     <el-upload
       multiple
       multiple
+      :disabled="disabled"
       :action="uploadImgUrl"
       :action="uploadImgUrl"
       list-type="picture-card"
       list-type="picture-card"
       :on-success="handleUploadSuccess"
       :on-success="handleUploadSuccess"
@@ -15,16 +16,20 @@
       :headers="headers"
       :headers="headers"
       :file-list="fileList"
       :file-list="fileList"
       :on-preview="handlePictureCardPreview"
       :on-preview="handlePictureCardPreview"
-      :class="{hide: this.fileList.length >= this.limit}"
+      :class="{ hide: this.fileList.length >= this.limit }"
     >
     >
       <i class="el-icon-plus"></i>
       <i class="el-icon-plus"></i>
     </el-upload>
     </el-upload>
-    
+
     <!-- 上传提示 -->
     <!-- 上传提示 -->
     <div class="el-upload__tip" slot="tip" v-if="showTip">
     <div class="el-upload__tip" slot="tip" v-if="showTip">
       请上传
       请上传
-      <template v-if="fileSize"> 大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b> </template>
-      <template v-if="fileType"> 格式为 <b style="color: #f56c6c">{{ fileType.join("/") }}</b> </template>
+      <template v-if="fileSize">
+        大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b>
+      </template>
+      <template v-if="fileType">
+        格式为 <b style="color: #f56c6c">{{ fileType.join("/") }}</b>
+      </template>
       的文件
       的文件
     </div>
     </div>
 
 
@@ -55,7 +60,7 @@ export default {
     },
     },
     // 大小限制(MB)
     // 大小限制(MB)
     fileSize: {
     fileSize: {
-       type: Number,
+      type: Number,
       default: 5,
       default: 5,
     },
     },
     // 文件类型, 例如['png', 'jpg', 'jpeg']
     // 文件类型, 例如['png', 'jpg', 'jpeg']
@@ -66,8 +71,13 @@ export default {
     // 是否显示提示
     // 是否显示提示
     isShowTip: {
     isShowTip: {
       type: Boolean,
       type: Boolean,
-      default: true
-    }
+      default: true,
+    },
+    // 是否禁用
+    disabled: {
+      type: Boolean,
+      default: false,
+    },
   },
   },
   data() {
   data() {
     return {
     return {
@@ -81,7 +91,7 @@ export default {
       headers: {
       headers: {
         Authorization: "Bearer " + getToken(),
         Authorization: "Bearer " + getToken(),
       },
       },
-      fileList: []
+      fileList: [],
     };
     };
   },
   },
   watch: {
   watch: {
@@ -89,14 +99,14 @@ export default {
       handler(val) {
       handler(val) {
         if (val) {
         if (val) {
           // 首先将值转为数组
           // 首先将值转为数组
-          const list = Array.isArray(val) ? val : this.value.split(',');
+          const list = Array.isArray(val) ? val : this.value.split(",");
           // 然后将数组转为对象数组
           // 然后将数组转为对象数组
-          this.fileList = list.map(item => {
+          this.fileList = list.map((item) => {
             if (typeof item === "string") {
             if (typeof item === "string") {
               if (item.indexOf(this.baseUrl) === -1) {
               if (item.indexOf(this.baseUrl) === -1) {
-                  item = { name: this.baseUrl + item, url: this.baseUrl + item };
+                item = { name: this.baseUrl + item, url: this.baseUrl + item };
               } else {
               } else {
-                  item = { name: item, url: item };
+                item = { name: item, url: item };
               }
               }
             }
             }
             return item;
             return item;
@@ -107,8 +117,8 @@ export default {
         }
         }
       },
       },
       deep: true,
       deep: true,
-      immediate: true
-    }
+      immediate: true,
+    },
   },
   },
   computed: {
   computed: {
     // 是否显示提示
     // 是否显示提示
@@ -119,8 +129,8 @@ export default {
   methods: {
   methods: {
     // 删除图片
     // 删除图片
     handleRemove(file, fileList) {
     handleRemove(file, fileList) {
-      const findex = this.fileList.map(f => f.name).indexOf(file.name);
-      if(findex > -1) {
+      const findex = this.fileList.map((f) => f.name).indexOf(file.name);
+      if (findex > -1) {
         this.fileList.splice(findex, 1);
         this.fileList.splice(findex, 1);
         this.$emit("input", this.listToString(this.fileList));
         this.$emit("input", this.listToString(this.fileList));
       }
       }
@@ -144,7 +154,7 @@ export default {
         if (file.name.lastIndexOf(".") > -1) {
         if (file.name.lastIndexOf(".") > -1) {
           fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1);
           fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1);
         }
         }
-        isImg = this.fileType.some(type => {
+        isImg = this.fileType.some((type) => {
           if (file.type.indexOf(type) > -1) return true;
           if (file.type.indexOf(type) > -1) return true;
           if (fileExtension && fileExtension.indexOf(type) > -1) return true;
           if (fileExtension && fileExtension.indexOf(type) > -1) return true;
           return false;
           return false;
@@ -154,7 +164,9 @@ export default {
       }
       }
 
 
       if (!isImg) {
       if (!isImg) {
-        this.$modal.msgError(`文件格式不正确, 请上传${this.fileType.join("/")}图片格式文件!`);
+        this.$modal.msgError(
+          `文件格式不正确, 请上传${this.fileType.join("/")}图片格式文件!`
+        );
         return false;
         return false;
       }
       }
       if (this.fileSize) {
       if (this.fileSize) {
@@ -188,25 +200,25 @@ export default {
       for (let i in list) {
       for (let i in list) {
         strs += list[i].url.replace(this.baseUrl, "") + separator;
         strs += list[i].url.replace(this.baseUrl, "") + separator;
       }
       }
-      return strs != '' ? strs.substr(0, strs.length - 1) : '';
-    }
-  }
+      return strs != "" ? strs.substr(0, strs.length - 1) : "";
+    },
+  },
 };
 };
 </script>
 </script>
 <style scoped lang="scss">
 <style scoped lang="scss">
 // .el-upload--picture-card 控制加号部分
 // .el-upload--picture-card 控制加号部分
 ::v-deep.hide .el-upload--picture-card {
 ::v-deep.hide .el-upload--picture-card {
-    display: none;
+  display: none;
 }
 }
 // 去掉动画效果
 // 去掉动画效果
 ::v-deep .el-list-enter-active,
 ::v-deep .el-list-enter-active,
 ::v-deep .el-list-leave-active {
 ::v-deep .el-list-leave-active {
-    transition: all 0s;
+  transition: all 0s;
 }
 }
 
 
-::v-deep .el-list-enter, .el-list-leave-active {
-    opacity: 0;
-    transform: translateY(0);
+::v-deep .el-list-enter,
+.el-list-leave-active {
+  opacity: 0;
+  transform: translateY(0);
 }
 }
 </style>
 </style>
-

+ 138 - 0
src/components/SelectRemote/index.vue

@@ -0,0 +1,138 @@
+<!-- el-select远程搜索公共组件 -->
+<template>
+  <el-select
+    :disabled="disabled"
+    style="width: 100%"
+    ref="selectRef"
+    v-loadmore="loadmore"
+    filterable
+    remote
+    @focus="getList"
+    :remote-method="remoteMethod"
+    v-model="selectId"
+    clearable
+    placeholder="请输入关键词搜索"
+    @change="onChange"
+  >
+    <el-option
+      v-for="item in options"
+      :key="item.id"
+      :label="item.selectLabel"
+      :value="item.id"
+    >
+    </el-option>
+  </el-select>
+</template>
+
+<script>
+import { getData } from "@/api/public";
+export default {
+  props: {
+    // 远程搜索的url
+    url: {
+      type: String,
+      default: "",
+    },
+    // 搜索的字段
+    field: {
+      type: String,
+      default: "",
+    },
+    value: {
+      type: Number | String,
+      default: "",
+    },
+    selectObj: {
+      type: Object,
+      default: () => {},
+    },
+    searchParams: {
+      type: Object,
+      default: () => {},
+    },
+    disabled: {
+      type: Boolean,
+      default: false,
+    },
+  },
+  data() {
+    return {
+      options: [],
+      stopLoading: false, // 加载开关,加载所有后端数据后控制懒加载是否继续执行,通过后端返回数据来控制
+      pageNum: 1,
+      total: 0,
+      selectId: null,
+    };
+  },
+  watch: {
+    selectObj(newVal) {
+      console.log(newVal);
+      if (newVal) {
+        this.selectId = newVal.id;
+        this.options = [newVal];
+      }
+    },
+  },
+  // created() {
+  //   this.getList();
+  // },
+  methods: {
+    onChange() {
+      this.$emit("input", this.selectId);
+    },
+    // 懒加载调用的方法
+    loadmore() {
+      if (this.options.length < this.total) {
+        this.pageNum++;
+        this.remoteMethod(this.$refs.selectRef.query, true);
+      }
+
+      // if (!this.stopLoading) {
+      //   this.pageNum++; // 搜索下一页
+      //   this.remoteMethod(this.$refs.selectRef.query, true); //调用后端接口获取下拉框数据,此时第二个参数必须传 true,懒加载方式调用后端接口函数
+      // }
+    },
+    // 输入框没有值时默认请求第一页8条数据
+    getList() {
+      let params = {
+        ...this.searchParams,
+        pageNum: 1,
+        pageSize: 8,
+      };
+      getData(this.url, params).then((res) => {
+        this.options = res.rows.map((item) => {
+          return {
+            ...item,
+            selectLabel: item[this.field],
+          };
+        });
+        this.total = res.total;
+      });
+    },
+    remoteMethod(query, lazy = false) {
+      this.stopLoading = true;
+      if (!lazy) {
+        // 如果不是懒加载,
+        this.options = []; // 把select选项数组重置为空
+        this.pageNum = 1; // 设置查询第一页
+      }
+      let params = {
+        pageNum: this.pageNum,
+        pageSize: 8,
+      };
+      params[this.field] = query;
+      getData(this.url, params).then((res) => {
+        let arr = res.rows.map((item) => {
+          return {
+            ...item,
+            selectLabel: item[this.field],
+          };
+        });
+        this.options = this.options.concat(arr);
+        this.total = res.total;
+        this.stopLoading = false;
+      });
+    },
+  },
+};
+</script>

+ 19 - 17
src/directive/index.js

@@ -1,23 +1,25 @@
-import hasRole from './permission/hasRole'
-import hasPermi from './permission/hasPermi'
-import dialogDrag from './dialog/drag'
-import dialogDragWidth from './dialog/dragWidth'
-import dialogDragHeight from './dialog/dragHeight'
-import clipboard from './module/clipboard'
+import hasRole from "./permission/hasRole";
+import hasPermi from "./permission/hasPermi";
+import dialogDrag from "./dialog/drag";
+import dialogDragWidth from "./dialog/dragWidth";
+import dialogDragHeight from "./dialog/dragHeight";
+import clipboard from "./module/clipboard";
+import loadmore from "./module/selectLoadmore";
 
 
-const install = function(Vue) {
-  Vue.directive('hasRole', hasRole)
-  Vue.directive('hasPermi', hasPermi)
-  Vue.directive('clipboard', clipboard)
-  Vue.directive('dialogDrag', dialogDrag)
-  Vue.directive('dialogDragWidth', dialogDragWidth)
-  Vue.directive('dialogDragHeight', dialogDragHeight)
-}
+const install = function (Vue) {
+  Vue.directive("hasRole", hasRole);
+  Vue.directive("hasPermi", hasPermi);
+  Vue.directive("clipboard", clipboard);
+  Vue.directive("dialogDrag", dialogDrag);
+  Vue.directive("dialogDragWidth", dialogDragWidth);
+  Vue.directive("dialogDragHeight", dialogDragHeight);
+  Vue.directive("loadmore", loadmore);
+};
 
 
 if (window.Vue) {
 if (window.Vue) {
-  window['hasRole'] = hasRole
-  window['hasPermi'] = hasPermi
+  window["hasRole"] = hasRole;
+  window["hasPermi"] = hasPermi;
   Vue.use(install); // eslint-disable-line
   Vue.use(install); // eslint-disable-line
 }
 }
 
 
-export default install
+export default install;

+ 23 - 0
src/directive/module/selectLoadmore.js

@@ -0,0 +1,23 @@
+/**
+ * v-loadmore 下拉框远程搜索触底加载(实现懒加载)
+ */
+
+export default {
+  bind(el, binding) {
+    // 下拉框对象
+    const SELECTWRAP_DOM = el.querySelector(
+      ".el-select-dropdown .el-select-dropdown__wrap"
+    );
+    // 给下拉框增加滚动监听,
+    SELECTWRAP_DOM.addEventListener("scroll", function () {
+      // scrollHeight:当前所有选项的高度
+      // scrollTop:滚动的距离
+      // clientHeight:下拉框的高度
+      const condition = this.scrollHeight - this.scrollTop <= this.clientHeight;
+      // 当滚动条滚动到最底下的时候执行接口加载下一页
+      if (condition) {
+        binding.value();
+      }
+    });
+  },
+};

+ 51 - 16
src/layout/components/Sidebar/Logo.vue

@@ -1,45 +1,80 @@
 <template>
 <template>
-  <div class="sidebar-logo-container" :class="{'collapse':collapse}" :style="{ backgroundColor: sideTheme === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground }">
+  <div
+    class="sidebar-logo-container"
+    :class="{ collapse: collapse }"
+    :style="{
+      backgroundColor:
+        sideTheme === 'theme-dark'
+          ? variables.menuBackground
+          : variables.menuLightBackground,
+    }"
+  >
     <transition name="sidebarLogoFade">
     <transition name="sidebarLogoFade">
-      <router-link v-if="collapse" key="collapse" class="sidebar-logo-link" to="/">
+      <router-link
+        v-if="collapse"
+        key="collapse"
+        class="sidebar-logo-link"
+        to="/"
+      >
         <img v-if="logo" :src="logo" class="sidebar-logo" />
         <img v-if="logo" :src="logo" class="sidebar-logo" />
-        <h1 v-else class="sidebar-title" :style="{ color: sideTheme === 'theme-dark' ? variables.logoTitleColor : variables.logoLightTitleColor }">{{ title }} </h1>
+        <h1
+          v-else
+          class="sidebar-title"
+          :style="{
+            color:
+              sideTheme === 'theme-dark'
+                ? variables.logoTitleColor
+                : variables.logoLightTitleColor,
+          }"
+        >
+          {{ title }}
+        </h1>
       </router-link>
       </router-link>
       <router-link v-else key="expand" class="sidebar-logo-link" to="/">
       <router-link v-else key="expand" class="sidebar-logo-link" to="/">
         <img v-if="logo" :src="logo" class="sidebar-logo" />
         <img v-if="logo" :src="logo" class="sidebar-logo" />
-        <h1 class="sidebar-title" :style="{ color: sideTheme === 'theme-dark' ? variables.logoTitleColor : variables.logoLightTitleColor }">{{ title }} </h1>
+        <h1
+          class="sidebar-title"
+          :style="{
+            color:
+              sideTheme === 'theme-dark'
+                ? variables.logoTitleColor
+                : variables.logoLightTitleColor,
+          }"
+        >
+          {{ title }}
+        </h1>
       </router-link>
       </router-link>
     </transition>
     </transition>
   </div>
   </div>
 </template>
 </template>
 
 
 <script>
 <script>
-import logoImg from '@/assets/logo/logo.png'
-import variables from '@/assets/styles/variables.scss'
+import logoImg from "@/assets/logo/logo.png";
+import variables from "@/assets/styles/variables.scss";
 
 
 export default {
 export default {
-  name: 'SidebarLogo',
+  name: "SidebarLogo",
   props: {
   props: {
     collapse: {
     collapse: {
       type: Boolean,
       type: Boolean,
-      required: true
-    }
+      required: true,
+    },
   },
   },
   computed: {
   computed: {
     variables() {
     variables() {
       return variables;
       return variables;
     },
     },
     sideTheme() {
     sideTheme() {
-      return this.$store.state.settings.sideTheme
-    }
+      return this.$store.state.settings.sideTheme;
+    },
   },
   },
   data() {
   data() {
     return {
     return {
-      title: '阿卜小程序管理系统',
-      logo: logoImg
-    }
-  }
-}
+      title: "泰兴反诈管理系统",
+      logo: logoImg,
+    };
+  },
+};
 </script>
 </script>
 
 
 <style lang="scss" scoped>
 <style lang="scss" scoped>

+ 145 - 0
src/views/infoManage/carouselManage/components/addAndEdit.vue

@@ -0,0 +1,145 @@
+<template>
+  <div v-loading="loading">
+    <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+      <el-form-item label="标题" prop="title">
+        <el-input v-model="form.title" placeholder="请输入标题" />
+      </el-form-item>
+      <el-form-item label="资讯标题" prop="infoId">
+        <SelectRemote
+          url="/info/infoContent/list"
+          field="title"
+          v-model="form.infoId"
+          :selectObj="selectObj"
+          :searchParams="searchParams"
+        />
+      </el-form-item>
+      <el-form-item label="图片" prop="img">
+        <image-upload :limit="1" v-model="form.img" />
+      </el-form-item>
+      <el-form-item label="排序" prop="sort">
+        <el-input-number
+          style="width: 100%"
+          v-model="form.sort"
+          :min="1"
+          :max="9999"
+          label="请输入排序"
+        ></el-input-number>
+      </el-form-item>
+      <el-form-item label="状态" prop="status">
+        <el-select
+          v-model="form.status"
+          placeholder="请选择状态"
+          style="width: 100%"
+        >
+          <el-option
+            v-for="dict in statusOption"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          ></el-option>
+        </el-select>
+      </el-form-item>
+    </el-form>
+    <div style="text-align: right">
+      <el-button type="primary" @click="handleConfirm">确 定</el-button>
+      <el-button @click="handleCancel">取 消</el-button>
+    </div>
+  </div>
+</template>
+
+<script>
+import SelectRemote from "@/components/SelectRemote";
+export default {
+  components: { SelectRemote },
+  props: {
+    data: {
+      type: Object,
+      default: () => {},
+    },
+    loading: {
+      type: Boolean,
+      default: false,
+    },
+  },
+  data() {
+    return {
+      // 选中的资讯标题
+      selectObj: {},
+      // 远程搜索框的查询条件
+      searchParams: {
+        checkStatus: "5",
+      },
+      // 状态组
+      statusOption: [
+        { value: "0", label: "启用" },
+        { value: "1", label: "停用" },
+      ],
+      form: {
+        title: "",
+        infoId: "",
+        img: "",
+        sort: "",
+        status: "",
+      },
+      rules: {
+        title: [{ required: true, trigger: "blur", message: "请输入标题" }],
+        infoId: [
+          { required: true, trigger: "change", message: "请选择资讯标题" },
+        ],
+        img: [{ required: true, trigger: "blur", message: "请上传图片" }],
+        sort: [{ required: true, trigger: "blur", message: "请输入排序" }],
+        status: [{ required: true, trigger: "change", message: "请选择状态" }],
+      },
+    };
+  },
+  watch: {
+    data: {
+      handler(newVal) {
+        if (newVal) {
+          this.form = {
+            id: newVal.id || "",
+            title: newVal.title || "",
+            infoId: newVal.infoId || "",
+            img: newVal.img || "",
+            sort: newVal.sort || "",
+            status: newVal.status || "",
+          };
+          this.selectObj = {
+            id: newVal.infoId || "",
+            selectLabel: newVal.infoTitle || "",
+          };
+          this.$nextTick(() => {
+            this.$refs.form && this.$refs.form.clearValidate();
+          });
+        }
+      },
+    },
+  },
+  methods: {
+    // 确定
+    handleConfirm() {
+      this.$refs.form.validate((valid) => {
+        if (valid) {
+          this.$emit("confirm", this.form);
+        }
+      });
+    },
+    // 取消
+    handleCancel() {
+      this.form = {
+        title: "",
+        infoId: "",
+        img: "",
+        sort: "",
+        status: "",
+      };
+      this.$nextTick(() => {
+        this.$refs.form && this.$refs.form.clearValidate();
+      });
+      this.$emit("cancel");
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped></style>

+ 327 - 0
src/views/infoManage/carouselManage/index.vue

@@ -0,0 +1,327 @@
+<template>
+  <div class="app-container">
+    <!-- 表单筛选 -->
+    <el-form
+      :model="queryParams"
+      ref="queryForm"
+      size="small"
+      inline
+      v-show="showSearch"
+      label-width="80px"
+    >
+      <el-form-item label="标题" prop="title">
+        <el-input
+          v-model="queryParams.title"
+          placeholder="请输入标题"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="资讯标题" prop="infoId">
+        <SelectRemote
+          url="/info/infoContent/list"
+          field="title"
+          v-model="queryParams.infoId"
+          :selectObj="selectObj"
+          :searchParams="searchParams"
+        />
+      </el-form-item>
+      <el-form-item label="状态" prop="status">
+        <el-select
+          v-model="queryParams.status"
+          placeholder="请选择状态"
+          clearable
+        >
+          <el-option
+            v-for="dict in statusOption"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="创建时间">
+        <el-date-picker
+          v-model="dateRange"
+          style="width: 100%"
+          value-format="yyyy-MM-dd"
+          type="daterange"
+          range-separator="-"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+        ></el-date-picker>
+      </el-form-item>
+      <el-form-item>
+        <el-button
+          type="primary"
+          icon="el-icon-search"
+          size="mini"
+          @click="handleQuery"
+          >搜索</el-button
+        >
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery"
+          >重置</el-button
+        >
+      </el-form-item>
+    </el-form>
+    <!-- 按钮组 -->
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          >新增</el-button
+        >
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="selectedRow.length < 1"
+          @click="handleDelete"
+          >删除</el-button
+        >
+      </el-col>
+      <right-toolbar
+        :showSearch.sync="showSearch"
+        @queryTable="getTableList"
+      ></right-toolbar>
+    </el-row>
+    <!-- 表格 -->
+    <el-table
+      v-loading="loading"
+      :data="tableList"
+      @selection-change="handleSelectionChange"
+    >
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="标题" align="center" prop="title" />
+      <el-table-column label="资讯标题" align="center" prop="infoTitle" />
+      <el-table-column label="图片" align="center" prop="img" width="100">
+        <template slot-scope="scope">
+          <image-preview :src="scope.row.img" :width="50" :height="50" />
+        </template>
+      </el-table-column>
+      <el-table-column label="排序" align="center" prop="sort" />
+      <el-table-column label="状态" align="center" prop="status">
+        <template slot-scope="scope">
+          <el-tag
+            effect="dark"
+            :type="scope.row.status === '0' ? 'success' : 'danger'"
+          >
+            {{ scope.row.status === "0" ? "启用" : "停用" }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="创建时间" align="center" prop="createTime" />
+      <el-table-column
+        label="操作"
+        align="center"
+        class-name="small-padding fixed-width"
+      >
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            >修改</el-button
+          >
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            >删除</el-button
+          >
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 分页 -->
+    <pagination
+      v-show="total > 0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getTableList"
+    />
+    <!-- 新增编辑弹窗 -->
+    <el-dialog
+      :title="title"
+      :visible.sync="dlgVisible"
+      append-to-body
+      width="30%"
+    >
+      <AddAndEdit
+        :loading="dlgLoading"
+        :data="formData"
+        @confirm="handleConfirm"
+        @cancel="handleCancel"
+      ></AddAndEdit>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import {
+  getList,
+  getDetail,
+  add,
+  update,
+  del,
+} from "@/api/infoManage/carouselManage";
+import SelectRemote from "@/components/SelectRemote";
+import AddAndEdit from "./components/addAndEdit.vue";
+export default {
+  name: "CarouselManage",
+  components: {
+    AddAndEdit,
+    SelectRemote,
+  },
+  data() {
+    return {
+      selectObj: {},
+      // 远程搜索框的查询条件
+      searchParams: {
+        checkStatus: "5",
+      },
+      // 显示搜索条件
+      showSearch: true,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        title: "",
+        infoId: "",
+        status: "",
+      },
+      // 时间
+      dateRange: [],
+      // 状态组
+      statusOption: [
+        { value: "0", label: "启用" },
+        { value: "1", label: "停用" },
+      ],
+      // 表格相关
+      loading: false,
+      tableList: [],
+      selectedRow: [],
+      total: 0,
+      //  弹窗相关
+      title: "",
+      dlgVisible: false,
+      formData: {},
+      dlgLoading: false,
+    };
+  },
+  created() {
+    this.getTableList();
+  },
+  methods: {
+    // 搜索
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getTableList();
+    },
+    // 重置
+    resetQuery() {
+      this.dateRange = [];
+      this.queryParams = {
+        pageNum: 1,
+        pageSize: 10,
+        title: "",
+        infoId: "",
+        status: "",
+      };
+      this.selectObj = {};
+      this.getTableList();
+    },
+    // 新增
+    handleAdd() {
+      this.title = "新增";
+      this.dlgVisible = true;
+      this.formData = {};
+    },
+    // 修改
+    handleUpdate(row) {
+      this.title = "编辑";
+      this.dlgVisible = true;
+      this.dlgLoading = true;
+      // const id = row.id || this.selectedRow[0].id;
+      getDetail(row.id)
+        .then((res) => {
+          if (res.code === 200) {
+            this.formData = { ...res.data, infoTitle: row.infoTitle };
+          }
+        })
+        .finally(() => (this.dlgLoading = false));
+    },
+    // 弹窗确认
+    handleConfirm(val) {
+      if (val.id) {
+        update(val).then((res) => {
+          if (res.code === 200) {
+            this.$modal.msgSuccess("编辑成功");
+            this.handleCancel();
+            this.getTableList();
+          }
+        });
+      } else {
+        add(val).then((res) => {
+          if (res.code === 200) {
+            this.$modal.msgSuccess("新增成功");
+            this.handleCancel();
+            this.getTableList();
+          }
+        });
+      }
+    },
+    // 弹窗取消
+    handleCancel() {
+      this.dlgVisible = false;
+    },
+    // 删除
+    handleDelete(row) {
+      const selectIds = this.selectedRow.map((item) => item.id);
+      const ids = row.id || selectIds;
+      this.$modal
+        .confirm("是否确认删除数据?")
+        .then(function () {
+          return del(ids);
+        })
+        .then(() => {
+          this.getTableList();
+          this.$modal.msgSuccess("删除成功");
+        })
+        .catch(() => {});
+    },
+    // 表格选中
+    handleSelectionChange(selection) {
+      this.selectedRow = selection;
+    },
+    // 表格当前行是否可选
+    selectable(row, index) {
+      return row.status === "1";
+    },
+    // 查询列表
+    getTableList() {
+      let params = this.addDateRange(this.queryParams, this.dateRange);
+      this.loading = true;
+      getList(params)
+        .then((res) => {
+          if (res.code === 200) {
+            this.tableList = res.rows;
+            this.total = res.total;
+          }
+        })
+        .finally(() => (this.loading = false));
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped></style>

+ 5 - 1
src/views/infoManage/classification/components/addAndEdit.vue

@@ -1,5 +1,5 @@
 <template>
 <template>
-  <div>
+  <div v-loading="loading">
     <el-form ref="form" :model="form" :rules="rules" label-width="80px">
     <el-form ref="form" :model="form" :rules="rules" label-width="80px">
       <el-form-item label="分类名称" prop="name">
       <el-form-item label="分类名称" prop="name">
         <el-input v-model="form.name" placeholder="请输入分类名称" />
         <el-input v-model="form.name" placeholder="请输入分类名称" />
@@ -50,6 +50,10 @@ export default {
       type: Object,
       type: Object,
       default: () => {},
       default: () => {},
     },
     },
+    loading: {
+      type: Boolean,
+      default: false,
+    },
   },
   },
   data() {
   data() {
     return {
     return {

+ 6 - 2
src/views/infoManage/classification/index.vue

@@ -233,7 +233,12 @@ export default {
     // 重置
     // 重置
     resetQuery() {
     resetQuery() {
       this.dateRange = [];
       this.dateRange = [];
-      this.resetForm("queryForm");
+      this.queryParams = {
+        pageNum: 1,
+        pageSize: 10,
+        name: "",
+        status: "",
+      };
       this.getTableList();
       this.getTableList();
     },
     },
     // 新增
     // 新增
@@ -306,7 +311,6 @@ export default {
     // 查询列表
     // 查询列表
     getTableList() {
     getTableList() {
       let params = this.addDateRange(this.queryParams, this.dateRange);
       let params = this.addDateRange(this.queryParams, this.dateRange);
-      console.log(params);
       this.loading = true;
       this.loading = true;
       getList(params)
       getList(params)
         .then((res) => {
         .then((res) => {

+ 220 - 0
src/views/infoManage/news/components/addAndEdit.vue

@@ -0,0 +1,220 @@
+<template>
+  <div v-loading="loading">
+    <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+      <el-form-item label="标题" prop="title">
+        <el-input
+          v-model="form.title"
+          placeholder="请输入标题"
+          :disabled="[3, 4].includes(dlgType)"
+        />
+      </el-form-item>
+      <el-form-item label="分类" prop="categoryId">
+        <SelectRemote
+          :disabled="[3, 4].includes(dlgType)"
+          url="/info/category/list"
+          field="name"
+          v-model="form.categoryId"
+          :selectObj="selectObj"
+          :searchParams="searchParams"
+        />
+      </el-form-item>
+      <el-form-item label="来源" prop="source" v-if="dlgType === 3">
+        <el-select
+          disabled
+          v-model="form.source"
+          placeholder="请选择来源"
+          style="width: 100%"
+        >
+          <el-option
+            v-for="dict in sourceOption"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          ></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="封面图" prop="banner">
+        <image-upload
+          :limit="1"
+          v-model="form.banner"
+          :disabled="[3, 4].includes(dlgType)"
+        />
+      </el-form-item>
+      <el-form-item label="正文内容" prop="content">
+        <el-input
+          type="textarea"
+          :rows="4"
+          v-model="form.content"
+          placeholder="请输入正文内容"
+          :disabled="[3, 4].includes(dlgType)"
+        />
+      </el-form-item>
+      <template v-if="dlgType === 3">
+        <el-form-item label="状态" prop="checkStatus">
+          <el-select
+            v-model="form.checkStatus"
+            placeholder="请选择状态"
+            style="width: 100%"
+            disabled
+          >
+            <el-option
+              v-for="dict in dict.type.check_status"
+              :key="dict.value"
+              :label="dict.label"
+              :value="dict.value"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+      </template>
+      <template v-if="[3, 4].includes(dlgType)">
+        <el-form-item label="审核结果" prop="checkResult">
+          <el-select
+            v-model="form.checkResult"
+            placeholder="请选择审核结果"
+            style="width: 100%"
+            :disabled="dlgType === 3"
+          >
+            <el-option
+              v-for="dict in dict.type.check_result"
+              :key="dict.value"
+              :label="dict.label"
+              :value="dict.value"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+          <el-input
+            type="textarea"
+            :rows="4"
+            v-model="form.remark"
+            placeholder="审核不通过时必填"
+            :disabled="dlgType === 3"
+          />
+        </el-form-item>
+      </template>
+    </el-form>
+    <div style="text-align: right" v-if="dlgType !== 3">
+      <el-button type="primary" @click="handleConfirm">确 定</el-button>
+      <el-button @click="handleCancel">取 消</el-button>
+    </div>
+    <div style="text-align: right" v-else>
+      <el-button @click="handleCancel">关 闭</el-button>
+    </div>
+  </div>
+</template>
+
+<script>
+import SelectRemote from "@/components/SelectRemote";
+export default {
+  components: { SelectRemote },
+  dicts: ["check_result", "check_status"],
+  props: {
+    data: {
+      type: Object,
+      default: () => {},
+    },
+    loading: {
+      type: Boolean,
+      default: false,
+    },
+    dlgType: {
+      // 弹窗类型  1 - 新增   2 - 修改   3 - 查看   4 - 审核
+      type: Number,
+      default: 1,
+    },
+  },
+  data() {
+    return {
+      // 选中的资讯标题
+      selectObj: {},
+      // 远程搜索框的查询条件
+      searchParams: {
+        status: "0",
+      },
+      // 状态组
+      sourceOption: [
+        { value: "0", label: "智能生成" },
+        { value: "1", label: "手工录入" },
+      ],
+      form: {
+        title: "",
+        categoryId: "",
+        source: "1", // 默认手工录入
+        banner: "",
+        content: "",
+        checkStatus: "1", // 审核状态,默认草稿
+        checkResult: "",
+        remark: "",
+      },
+      rules: {
+        title: [{ required: true, trigger: "blur", message: "请输入标题" }],
+        categoryId: [
+          { required: true, trigger: "change", message: "请选择分类" },
+        ],
+        banner: [{ required: true, trigger: "blur", message: "请上传封面图" }],
+        content: [
+          { required: true, trigger: "blur", message: "请输入正文内容" },
+        ],
+      },
+    };
+  },
+  watch: {
+    data: {
+      handler(newVal) {
+        if (newVal) {
+          this.form = {
+            id: newVal.id || "",
+            title: newVal.title || "",
+            categoryId: newVal.categoryId || "",
+            source: newVal.source || "1",
+            banner: newVal.banner || "",
+            content: newVal.content || "",
+            checkStatus: newVal.checkStatus || "1",
+            checkResult: newVal.checkResult || "",
+            remark: newVal.remark || "",
+          };
+          this.selectObj = {
+            id: newVal.categoryId || "",
+            selectLabel: newVal.categoryName || "",
+          };
+          this.$nextTick(() => {
+            this.$refs.form && this.$refs.form.clearValidate();
+          });
+        }
+      },
+    },
+  },
+  methods: {
+    // 确定
+    handleConfirm() {
+      this.$refs.form.validate((valid) => {
+        if (valid) {
+          if (this.form.checkResult == "1" && !this.form.remark)
+            return this.$modal.msgError("请填写审核不通过的原因");
+          if (this.dlgType === 4) this.form.checkStatus = "3";
+          this.$emit("confirm", this.form);
+        }
+      });
+    },
+    // 取消
+    handleCancel() {
+      this.form = {
+        title: "",
+        categoryId: "",
+        source: "1", // 默认手工录入
+        banner: "",
+        content: "",
+        checkStatus: "1", // 审核状态,默认草稿
+        checkResult: "",
+        remark: "",
+      };
+      this.$nextTick(() => {
+        this.$refs.form && this.$refs.form.clearValidate();
+      });
+      this.$emit("cancel");
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped></style>

+ 526 - 0
src/views/infoManage/news/index.vue

@@ -0,0 +1,526 @@
+<template>
+  <div class="app-container">
+    <!-- 表单筛选 -->
+    <el-form
+      :model="queryParams"
+      ref="queryForm"
+      size="small"
+      inline
+      v-show="showSearch"
+      label-width="80px"
+    >
+      <el-form-item label="分类名称" prop="categoryId">
+        <SelectRemote
+          url="/info/category/list"
+          field="name"
+          v-model="queryParams.categoryId"
+          :selectObj="selectObj"
+          :searchParams="searchParams"
+        />
+      </el-form-item>
+      <el-form-item label="状态" prop="checkStatus">
+        <el-select
+          v-model="queryParams.checkStatus"
+          placeholder="请选择状态"
+          clearable
+        >
+          <el-option
+            v-for="dict in dict.type.check_status"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="创建时间">
+        <el-date-picker
+          v-model="dateRange"
+          style="width: 100%"
+          value-format="yyyy-MM-dd"
+          type="daterange"
+          range-separator="-"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+        ></el-date-picker>
+      </el-form-item>
+      <el-form-item label="修改时间">
+        <el-date-picker
+          v-model="updateDateRange"
+          style="width: 100%"
+          value-format="yyyy-MM-dd"
+          type="daterange"
+          range-separator="-"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+        ></el-date-picker>
+      </el-form-item>
+      <el-form-item>
+        <el-button
+          type="primary"
+          icon="el-icon-search"
+          size="mini"
+          @click="handleQuery"
+          >搜索</el-button
+        >
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery"
+          >重置</el-button
+        >
+      </el-form-item>
+    </el-form>
+    <!-- 按钮组 -->
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          >新增</el-button
+        >
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAutogeneration"
+          >智能生成</el-button
+        >
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="selectedRow.length < 1"
+          @click="handleDelete"
+          >删除</el-button
+        >
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="selectedRow.length !== 1"
+          @click="handleApply"
+          >申请审核</el-button
+        >
+      </el-col>
+      <right-toolbar
+        :showSearch.sync="showSearch"
+        @queryTable="getTableList"
+      ></right-toolbar>
+    </el-row>
+    <!-- 表格 -->
+    <el-table
+      v-loading="loading"
+      :data="tableList"
+      @selection-change="handleSelectionChange"
+    >
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="标题" align="center" prop="title" />
+      <el-table-column label="分类" align="center" prop="categoryName" />
+      <el-table-column
+        label="来源"
+        align="center"
+        prop="source"
+        :formatter="sourceFormatter"
+      />
+      <el-table-column label="状态" align="center" prop="checkStatus">
+        <template slot-scope="scope">
+          <dict-tag
+            :options="dict.type.check_status"
+            :value="scope.row.checkStatus"
+          />
+        </template>
+      </el-table-column>
+      <el-table-column label="审核结果" align="center" prop="checkResult">
+        <template slot-scope="scope">
+          <dict-tag
+            :options="dict.type.check_result"
+            :value="scope.row.checkResult"
+            v-if="scope.row.checkResult"
+          />
+          <div v-else>无</div>
+        </template>
+      </el-table-column>
+      <el-table-column
+        label="发布时间"
+        align="center"
+        prop="publishTime"
+        width="100"
+      />
+      <el-table-column
+        label="撤销时间"
+        align="center"
+        prop="cancelTime"
+        width="100"
+      />
+      <el-table-column
+        label="创建时间"
+        align="center"
+        prop="createTime"
+        width="100"
+      />
+      <el-table-column
+        label="修改时间"
+        align="center"
+        prop="updateTime"
+        width="100"
+      />
+      <el-table-column
+        label="操作"
+        align="center"
+        class-name="small-padding fixed-width"
+      >
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-view"
+            @click="handleDetail(scope.row)"
+            >查看</el-button
+          >
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-if="
+              scope.row.checkStatus === '1' ||
+              (scope.row.checkStatus === '3' && scope.row.checkResult === '2')
+            "
+            >修改</el-button
+          >
+          <!-- 后期需核实删除按钮展示是否有限制(目前是已发布的数据不能删除) -->
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-if="scope.row.checkStatus !== '5'"
+            >删除</el-button
+          >
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-document-checked"
+            @click="handleReview(scope.row)"
+            v-if="scope.row.checkStatus === '2'"
+            >审核</el-button
+          >
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-upload2"
+            @click="handleRelease(scope.row)"
+            v-if="
+              scope.row.checkResult === '2' && scope.row.checkStatus !== '5'
+            "
+            >发布</el-button
+          >
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-download"
+            @click="handleRevoke(scope.row)"
+            v-if="scope.row.checkStatus === '5'"
+            >撤销发布</el-button
+          >
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-s-order"
+            @click="handleRecord(scope.row)"
+            >操作记录</el-button
+          >
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 分页 -->
+    <pagination
+      v-show="total > 0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getTableList"
+    />
+    <!-- 新增编辑弹窗 -->
+    <el-dialog
+      :title="title"
+      :visible.sync="dlgVisible"
+      append-to-body
+      width="30%"
+    >
+      <AddAndEdit
+        :loading="dlgLoading"
+        :data="formData"
+        :dlgType="dlgType"
+        @confirm="handleConfirm"
+        @cancel="handleCancel"
+      ></AddAndEdit>
+    </el-dialog>
+    <!-- 操作记录弹窗 -->
+    <el-dialog title="操作记录" :visible.sync="recordVisible" append-to-body>
+      <!-- 表格 -->
+      <el-table v-loading="recordLoading" :data="recordList">
+        <el-table-column label="操作类型" align="center" prop="title" />
+        <el-table-column label="操作时间" align="center" prop="checkStatus" />
+        <el-table-column label="操作人" align="center" prop="checkResult" />
+      </el-table>
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="recordVisible = false">关 闭</el-button>
+      </span>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { getList, getDetail, add, update, del } from "@/api/infoManage/news";
+import SelectRemote from "@/components/SelectRemote";
+import AddAndEdit from "./components/addAndEdit.vue";
+export default {
+  name: "News",
+  dicts: ["check_status", "check_result"],
+  components: {
+    AddAndEdit,
+    SelectRemote,
+  },
+  data() {
+    return {
+      selectObj: {},
+      // 远程搜索框的查询条件
+      searchParams: {
+        status: "0",
+      },
+      // 显示搜索条件
+      showSearch: true,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        categoryId: "",
+        checkStatus: "",
+      },
+      // 时间
+      dateRange: [],
+      updateDateRange: [],
+      // 来源组
+      sourceOption: [
+        { value: "0", label: "智能生成" },
+        { value: "1", label: "手工录入" },
+      ],
+      // 分类组
+      categoryOption: [],
+      // 表格相关
+      loading: false,
+      tableList: [],
+      selectedRow: [],
+      total: 0,
+      //  弹窗相关
+      title: "",
+      dlgVisible: false,
+      formData: {},
+      dlgLoading: false,
+      dlgType: 1, // 弹窗类型  1 - 新增   2 - 修改   3 - 查看   4 - 审核
+      // 操作记录弹窗相关
+      recordVisible: false,
+      recordLoading: false,
+      recordList: [],
+    };
+  },
+  created() {
+    this.getTableList();
+  },
+  methods: {
+    // 来源值映射
+    sourceFormatter(row) {
+      return this.selectDictLabel(this.sourceOption, row.source);
+    },
+    // 搜索
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getTableList();
+    },
+    // 重置
+    resetQuery() {
+      this.dateRange = [];
+      this.updateDateRange = [];
+      this.queryParams = {
+        pageNum: 1,
+        pageSize: 10,
+        categoryId: "",
+        checkStatus: "",
+      };
+      this.selectObj = {};
+      this.getTableList();
+    },
+    // 提交,发布,撤销发布公共部分
+    handleCommon(params, tip) {
+      this.$modal
+        .confirm(tip)
+        .then(function () {
+          return update(params);
+        })
+        .then(() => {
+          this.getTableList();
+          this.$modal.msgSuccess("操作成功");
+        })
+        .catch(() => {});
+    },
+    // 撤销发布  checkStatus   6
+    handleRevoke(row) {
+      let params = {
+        ...row,
+        checkStatus: "6",
+      };
+      let tip = "是否确认撤销发布?";
+      this.handleCommon(params, tip);
+    },
+    // 发布 checkStatus   5
+    handleRelease(row) {
+      let params = {
+        ...row,
+        checkStatus: "5",
+      };
+      let tip = "是否确认发布?";
+      this.handleCommon(params, tip);
+    },
+    // 审核
+    handleReview(row) {
+      this.title = "审核";
+      this.dlgVisible = true;
+      this.dlgType = 4;
+      this.dlgLoading = true;
+      getDetail(row.id)
+        .then((res) => {
+          if (res.code === 200) {
+            this.formData = { ...res.data, categoryName: row.categoryName };
+          }
+        })
+        .finally(() => (this.dlgLoading = false));
+    },
+    // 申请审核
+    handleApply() {
+      let obj = this.selectedRow[0];
+      if (obj.checkStatus !== "1")
+        return this.$modal.msgError("当前数据不是草稿状态,无法提交");
+      let params = {
+        ...this.selectedRow[0],
+        checkStatus: "2", // 审核状态由草稿 1 改为 待审核 2
+      };
+      let tip = "是否确认提交审核?";
+      this.handleCommon(params, tip);
+    },
+    // 智能生成(新增一条列表数据)
+    handleAutogeneration() {},
+    // 新增(手动新增的来源都是手工录入)
+    handleAdd() {
+      this.title = "新增";
+      this.dlgType = 1;
+      this.dlgVisible = true;
+      this.formData = {};
+    },
+    // 查看
+    handleDetail(row) {
+      this.title = "查看";
+      this.dlgVisible = true;
+      this.dlgType = 3;
+      this.dlgLoading = true;
+      getDetail(row.id)
+        .then((res) => {
+          if (res.code === 200) {
+            this.formData = { ...res.data, categoryName: row.categoryName };
+          }
+        })
+        .finally(() => (this.dlgLoading = false));
+    },
+    // 修改
+    handleUpdate(row) {
+      this.title = "编辑";
+      this.dlgType = 2;
+      this.dlgVisible = true;
+      this.dlgLoading = true;
+      getDetail(row.id)
+        .then((res) => {
+          if (res.code === 200) {
+            this.formData = { ...res.data, categoryName: row.categoryName };
+          }
+        })
+        .finally(() => (this.dlgLoading = false));
+    },
+    // 弹窗确认
+    handleConfirm(val) {
+      if (val.id) {
+        update(val).then((res) => {
+          if (res.code === 200) {
+            this.$modal.msgSuccess("编辑成功");
+            this.handleCancel();
+            this.getTableList();
+          }
+        });
+      } else {
+        add(val).then((res) => {
+          if (res.code === 200) {
+            this.$modal.msgSuccess("新增成功");
+            this.handleCancel();
+            this.getTableList();
+          }
+        });
+      }
+    },
+    // 弹窗取消
+    handleCancel() {
+      this.dlgVisible = false;
+    },
+    // 删除
+    handleDelete(row) {
+      const selectIds = this.selectedRow.map((item) => item.id);
+      const ids = row.id || selectIds;
+      this.$modal
+        .confirm("是否确认删除数据?")
+        .then(function () {
+          return del(ids);
+        })
+        .then(() => {
+          this.getTableList();
+          this.$modal.msgSuccess("删除成功");
+        })
+        .catch(() => {});
+    },
+    // 操作记录
+    handleRecord() {
+      this.recordVisible = true;
+    },
+    // 表格选中
+    handleSelectionChange(selection) {
+      this.selectedRow = selection;
+    },
+    // 查询列表
+    getTableList() {
+      let params1 = this.addDateRange(this.queryParams, this.dateRange);
+      let params2 = this.addDateRange(
+        params1,
+        this.updateDateRange,
+        "updateTime"
+      );
+      this.loading = true;
+      getList(params2)
+        .then((res) => {
+          if (res.code === 200) {
+            this.tableList = res.rows;
+            this.total = res.total;
+          }
+        })
+        .finally(() => (this.loading = false));
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped></style>

+ 72 - 40
src/views/login.vue

@@ -1,7 +1,12 @@
 <template>
 <template>
   <div class="login">
   <div class="login">
-    <el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form">
-      <h3 class="title">阿卜Coder小程序管理系统</h3>
+    <el-form
+      ref="loginForm"
+      :model="loginForm"
+      :rules="loginRules"
+      class="login-form"
+    >
+      <h3 class="title">泰兴反诈管理系统</h3>
       <el-form-item prop="username">
       <el-form-item prop="username">
         <el-input
         <el-input
           v-model="loginForm.username"
           v-model="loginForm.username"
@@ -9,7 +14,11 @@
           auto-complete="off"
           auto-complete="off"
           placeholder="账号"
           placeholder="账号"
         >
         >
-          <svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" />
+          <svg-icon
+            slot="prefix"
+            icon-class="user"
+            class="el-input__icon input-icon"
+          />
         </el-input>
         </el-input>
       </el-form-item>
       </el-form-item>
       <el-form-item prop="password">
       <el-form-item prop="password">
@@ -20,7 +29,11 @@
           placeholder="密码"
           placeholder="密码"
           @keyup.enter.native="handleLogin"
           @keyup.enter.native="handleLogin"
         >
         >
-          <svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />
+          <svg-icon
+            slot="prefix"
+            icon-class="password"
+            class="el-input__icon input-icon"
+          />
         </el-input>
         </el-input>
       </el-form-item>
       </el-form-item>
       <el-form-item prop="code" v-if="captchaOnOff">
       <el-form-item prop="code" v-if="captchaOnOff">
@@ -31,26 +44,36 @@
           style="width: 63%"
           style="width: 63%"
           @keyup.enter.native="handleLogin"
           @keyup.enter.native="handleLogin"
         >
         >
-          <svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" />
+          <svg-icon
+            slot="prefix"
+            icon-class="validCode"
+            class="el-input__icon input-icon"
+          />
         </el-input>
         </el-input>
         <div class="login-code">
         <div class="login-code">
-          <img :src="codeUrl" @click="getCode" class="login-code-img"/>
+          <img :src="codeUrl" @click="getCode" class="login-code-img" />
         </div>
         </div>
       </el-form-item>
       </el-form-item>
-      <el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;">记住密码</el-checkbox>
-      <el-form-item style="width:100%;">
+      <el-checkbox
+        v-model="loginForm.rememberMe"
+        style="margin: 0px 0px 25px 0px"
+        >记住密码</el-checkbox
+      >
+      <el-form-item style="width: 100%">
         <el-button
         <el-button
           :loading="loading"
           :loading="loading"
           size="medium"
           size="medium"
           type="primary"
           type="primary"
-          style="width:100%;"
+          style="width: 100%"
           @click.native.prevent="handleLogin"
           @click.native.prevent="handleLogin"
         >
         >
           <span v-if="!loading">登 录</span>
           <span v-if="!loading">登 录</span>
           <span v-else>登 录 中...</span>
           <span v-else>登 录 中...</span>
         </el-button>
         </el-button>
-        <div style="float: right;" v-if="register">
-          <router-link class="link-type" :to="'/register'">立即注册</router-link>
+        <div style="float: right" v-if="register">
+          <router-link class="link-type" :to="'/register'"
+            >立即注册</router-link
+          >
         </div>
         </div>
       </el-form-item>
       </el-form-item>
     </el-form>
     </el-form>
@@ -64,7 +87,7 @@
 <script>
 <script>
 import { getCodeImg } from "@/api/login";
 import { getCodeImg } from "@/api/login";
 import Cookies from "js-cookie";
 import Cookies from "js-cookie";
-import { encrypt, decrypt } from '@/utils/jsencrypt'
+import { encrypt, decrypt } from "@/utils/jsencrypt";
 
 
 export default {
 export default {
   name: "Login",
   name: "Login",
@@ -72,36 +95,36 @@ export default {
     return {
     return {
       codeUrl: "",
       codeUrl: "",
       loginForm: {
       loginForm: {
-        username: "testadmin",
+        username: "admin",
         password: "admin123",
         password: "admin123",
         rememberMe: false,
         rememberMe: false,
         code: "",
         code: "",
-        uuid: ""
+        uuid: "",
       },
       },
       loginRules: {
       loginRules: {
         username: [
         username: [
-          { required: true, trigger: "blur", message: "请输入您的账号" }
+          { required: true, trigger: "blur", message: "请输入您的账号" },
         ],
         ],
         password: [
         password: [
-          { required: true, trigger: "blur", message: "请输入您的密码" }
+          { required: true, trigger: "blur", message: "请输入您的密码" },
         ],
         ],
-        code: [{ required: true, trigger: "change", message: "请输入验证码" }]
+        code: [{ required: true, trigger: "change", message: "请输入验证码" }],
       },
       },
       loading: false,
       loading: false,
       // 验证码开关
       // 验证码开关
       captchaOnOff: true,
       captchaOnOff: true,
       // 注册开关
       // 注册开关
       register: false,
       register: false,
-      redirect: undefined
+      redirect: undefined,
     };
     };
   },
   },
   watch: {
   watch: {
     $route: {
     $route: {
-      handler: function(route) {
+      handler: function (route) {
         this.redirect = route.query && route.query.redirect;
         this.redirect = route.query && route.query.redirect;
       },
       },
-      immediate: true
-    }
+      immediate: true,
+    },
   },
   },
   created() {
   created() {
     this.getCode();
     this.getCode();
@@ -109,8 +132,9 @@ export default {
   },
   },
   methods: {
   methods: {
     getCode() {
     getCode() {
-      getCodeImg().then(res => {
-        this.captchaOnOff = res.captchaOnOff === undefined ? true : res.captchaOnOff;
+      getCodeImg().then((res) => {
+        this.captchaOnOff =
+          res.captchaOnOff === undefined ? true : res.captchaOnOff;
         if (this.captchaOnOff) {
         if (this.captchaOnOff) {
           this.codeUrl = "data:image/gif;base64," + res.img;
           this.codeUrl = "data:image/gif;base64," + res.img;
           this.loginForm.uuid = res.uuid;
           this.loginForm.uuid = res.uuid;
@@ -120,38 +144,46 @@ export default {
     getCookie() {
     getCookie() {
       const username = Cookies.get("username");
       const username = Cookies.get("username");
       const password = Cookies.get("password");
       const password = Cookies.get("password");
-      const rememberMe = Cookies.get('rememberMe')
+      const rememberMe = Cookies.get("rememberMe");
       this.loginForm = {
       this.loginForm = {
         username: username === undefined ? this.loginForm.username : username,
         username: username === undefined ? this.loginForm.username : username,
-        password: password === undefined ? this.loginForm.password : decrypt(password),
-        rememberMe: rememberMe === undefined ? false : Boolean(rememberMe)
+        password:
+          password === undefined ? this.loginForm.password : decrypt(password),
+        rememberMe: rememberMe === undefined ? false : Boolean(rememberMe),
       };
       };
     },
     },
     handleLogin() {
     handleLogin() {
-      this.$refs.loginForm.validate(valid => {
+      this.$refs.loginForm.validate((valid) => {
         if (valid) {
         if (valid) {
           this.loading = true;
           this.loading = true;
           if (this.loginForm.rememberMe) {
           if (this.loginForm.rememberMe) {
             Cookies.set("username", this.loginForm.username, { expires: 30 });
             Cookies.set("username", this.loginForm.username, { expires: 30 });
-            Cookies.set("password", encrypt(this.loginForm.password), { expires: 30 });
-            Cookies.set('rememberMe', this.loginForm.rememberMe, { expires: 30 });
+            Cookies.set("password", encrypt(this.loginForm.password), {
+              expires: 30,
+            });
+            Cookies.set("rememberMe", this.loginForm.rememberMe, {
+              expires: 30,
+            });
           } else {
           } else {
             Cookies.remove("username");
             Cookies.remove("username");
             Cookies.remove("password");
             Cookies.remove("password");
-            Cookies.remove('rememberMe');
+            Cookies.remove("rememberMe");
           }
           }
-          this.$store.dispatch("Login", this.loginForm).then(() => {
-            this.$router.push({ path: this.redirect || "/" }).catch(()=>{});
-          }).catch(() => {
-            this.loading = false;
-            if (this.captchaOnOff) {
-              this.getCode();
-            }
-          });
+          this.$store
+            .dispatch("Login", this.loginForm)
+            .then(() => {
+              this.$router.push({ path: this.redirect || "/" }).catch(() => {});
+            })
+            .catch(() => {
+              this.loading = false;
+              if (this.captchaOnOff) {
+                this.getCode();
+              }
+            });
         }
         }
       });
       });
-    }
-  }
+    },
+  },
 };
 };
 </script>
 </script>
 
 

+ 86 - 37
src/views/register.vue

@@ -1,10 +1,24 @@
 <template>
 <template>
   <div class="register">
   <div class="register">
-    <el-form ref="registerForm" :model="registerForm" :rules="registerRules" class="register-form">
-      <h3 class="title">阿卜小程序管理系统</h3>
+    <el-form
+      ref="registerForm"
+      :model="registerForm"
+      :rules="registerRules"
+      class="register-form"
+    >
+      <h3 class="title">泰兴反诈管理系统</h3>
       <el-form-item prop="username">
       <el-form-item prop="username">
-        <el-input v-model="registerForm.username" type="text" auto-complete="off" placeholder="账号">
-          <svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" />
+        <el-input
+          v-model="registerForm.username"
+          type="text"
+          auto-complete="off"
+          placeholder="账号"
+        >
+          <svg-icon
+            slot="prefix"
+            icon-class="user"
+            class="el-input__icon input-icon"
+          />
         </el-input>
         </el-input>
       </el-form-item>
       </el-form-item>
       <el-form-item prop="password">
       <el-form-item prop="password">
@@ -15,7 +29,11 @@
           placeholder="密码"
           placeholder="密码"
           @keyup.enter.native="handleRegister"
           @keyup.enter.native="handleRegister"
         >
         >
-          <svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />
+          <svg-icon
+            slot="prefix"
+            icon-class="password"
+            class="el-input__icon input-icon"
+          />
         </el-input>
         </el-input>
       </el-form-item>
       </el-form-item>
       <el-form-item prop="confirmPassword">
       <el-form-item prop="confirmPassword">
@@ -26,7 +44,11 @@
           placeholder="确认密码"
           placeholder="确认密码"
           @keyup.enter.native="handleRegister"
           @keyup.enter.native="handleRegister"
         >
         >
-          <svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />
+          <svg-icon
+            slot="prefix"
+            icon-class="password"
+            class="el-input__icon input-icon"
+          />
         </el-input>
         </el-input>
       </el-form-item>
       </el-form-item>
       <el-form-item prop="code" v-if="captchaOnOff">
       <el-form-item prop="code" v-if="captchaOnOff">
@@ -37,25 +59,31 @@
           style="width: 63%"
           style="width: 63%"
           @keyup.enter.native="handleRegister"
           @keyup.enter.native="handleRegister"
         >
         >
-          <svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" />
+          <svg-icon
+            slot="prefix"
+            icon-class="validCode"
+            class="el-input__icon input-icon"
+          />
         </el-input>
         </el-input>
         <div class="register-code">
         <div class="register-code">
-          <img :src="codeUrl" @click="getCode" class="register-code-img"/>
+          <img :src="codeUrl" @click="getCode" class="register-code-img" />
         </div>
         </div>
       </el-form-item>
       </el-form-item>
-      <el-form-item style="width:100%;">
+      <el-form-item style="width: 100%">
         <el-button
         <el-button
           :loading="loading"
           :loading="loading"
           size="medium"
           size="medium"
           type="primary"
           type="primary"
-          style="width:100%;"
+          style="width: 100%"
           @click.native.prevent="handleRegister"
           @click.native.prevent="handleRegister"
         >
         >
           <span v-if="!loading">注 册</span>
           <span v-if="!loading">注 册</span>
           <span v-else>注 册 中...</span>
           <span v-else>注 册 中...</span>
         </el-button>
         </el-button>
-        <div style="float: right;">
-          <router-link class="link-type" :to="'/login'">使用已有账户登录</router-link>
+        <div style="float: right">
+          <router-link class="link-type" :to="'/login'"
+            >使用已有账户登录</router-link
+          >
         </div>
         </div>
       </el-form-item>
       </el-form-item>
     </el-form>
     </el-form>
@@ -86,25 +114,35 @@ export default {
         password: "",
         password: "",
         confirmPassword: "",
         confirmPassword: "",
         code: "",
         code: "",
-        uuid: ""
+        uuid: "",
       },
       },
       registerRules: {
       registerRules: {
         username: [
         username: [
           { required: true, trigger: "blur", message: "请输入您的账号" },
           { required: true, trigger: "blur", message: "请输入您的账号" },
-          { min: 2, max: 20, message: '用户账号长度必须介于 2 和 20 之间', trigger: 'blur' }
+          {
+            min: 2,
+            max: 20,
+            message: "用户账号长度必须介于 2 和 20 之间",
+            trigger: "blur",
+          },
         ],
         ],
         password: [
         password: [
           { required: true, trigger: "blur", message: "请输入您的密码" },
           { required: true, trigger: "blur", message: "请输入您的密码" },
-          { min: 5, max: 20, message: '用户密码长度必须介于 5 和 20 之间', trigger: 'blur' }
+          {
+            min: 5,
+            max: 20,
+            message: "用户密码长度必须介于 5 和 20 之间",
+            trigger: "blur",
+          },
         ],
         ],
         confirmPassword: [
         confirmPassword: [
           { required: true, trigger: "blur", message: "请再次输入您的密码" },
           { required: true, trigger: "blur", message: "请再次输入您的密码" },
-          { required: true, validator: equalToPassword, trigger: "blur" }
+          { required: true, validator: equalToPassword, trigger: "blur" },
         ],
         ],
-        code: [{ required: true, trigger: "change", message: "请输入验证码" }]
+        code: [{ required: true, trigger: "change", message: "请输入验证码" }],
       },
       },
       loading: false,
       loading: false,
-      captchaOnOff: true
+      captchaOnOff: true,
     };
     };
   },
   },
   created() {
   created() {
@@ -112,8 +150,9 @@ export default {
   },
   },
   methods: {
   methods: {
     getCode() {
     getCode() {
-      getCodeImg().then(res => {
-        this.captchaOnOff = res.captchaOnOff === undefined ? true : res.captchaOnOff;
+      getCodeImg().then((res) => {
+        this.captchaOnOff =
+          res.captchaOnOff === undefined ? true : res.captchaOnOff;
         if (this.captchaOnOff) {
         if (this.captchaOnOff) {
           this.codeUrl = "data:image/gif;base64," + res.img;
           this.codeUrl = "data:image/gif;base64," + res.img;
           this.registerForm.uuid = res.uuid;
           this.registerForm.uuid = res.uuid;
@@ -121,27 +160,37 @@ export default {
       });
       });
     },
     },
     handleRegister() {
     handleRegister() {
-      this.$refs.registerForm.validate(valid => {
+      this.$refs.registerForm.validate((valid) => {
         if (valid) {
         if (valid) {
           this.loading = true;
           this.loading = true;
-          register(this.registerForm).then(res => {
-            const username = this.registerForm.username;
-            this.$alert("<font color='red'>恭喜你,您的账号 " + username + " 注册成功!</font>", '系统提示', {
-              dangerouslyUseHTMLString: true,
-              type: 'success'
-            }).then(() => {
-              this.$router.push("/login");
-            }).catch(() => {});
-          }).catch(() => {
-            this.loading = false;
-            if (this.captchaOnOff) {
-              this.getCode();
-            }
-          })
+          register(this.registerForm)
+            .then((res) => {
+              const username = this.registerForm.username;
+              this.$alert(
+                "<font color='red'>恭喜你,您的账号 " +
+                  username +
+                  " 注册成功!</font>",
+                "系统提示",
+                {
+                  dangerouslyUseHTMLString: true,
+                  type: "success",
+                }
+              )
+                .then(() => {
+                  this.$router.push("/login");
+                })
+                .catch(() => {});
+            })
+            .catch(() => {
+              this.loading = false;
+              if (this.captchaOnOff) {
+                this.getCode();
+              }
+            });
         }
         }
       });
       });
-    }
-  }
+    },
+  },
 };
 };
 </script>
 </script>
 
 

+ 3 - 2
vue.config.js

@@ -7,7 +7,7 @@ function resolve(dir) {
 
 
 const CompressionPlugin = require("compression-webpack-plugin");
 const CompressionPlugin = require("compression-webpack-plugin");
 
 
-const name = process.env.VUE_APP_TITLE || "阿卜小程序管理系统"; // 网页标题
+const name = process.env.VUE_APP_TITLE || "泰兴反诈管理系统"; // 网页标题
 
 
 const port = process.env.port || process.env.npm_config_port || 80; // 端口
 const port = process.env.port || process.env.npm_config_port || 80; // 端口
 
 
@@ -36,7 +36,8 @@ module.exports = {
       // detail: https://cli.vuejs.org/config/#devserver-proxy
       // detail: https://cli.vuejs.org/config/#devserver-proxy
       [process.env.VUE_APP_BASE_API]: {
       [process.env.VUE_APP_BASE_API]: {
         // target: `http://localhost:8083`,
         // target: `http://localhost:8083`,
-        target: `http://172.16.8.30:8083`,
+        // target: `http://172.16.8.37:8083`,
+        target: `http://192.168.21.12:8083`,
         changeOrigin: true,
         changeOrigin: true,
         pathRewrite: {
         pathRewrite: {
           ["^" + process.env.VUE_APP_BASE_API]: "",
           ["^" + process.env.VUE_APP_BASE_API]: "",