lex %!s(int64=3) %!d(string=hai) anos
pai
achega
2d8a6091ee

+ 22 - 2
src/main.js

@@ -52,7 +52,13 @@ import {
   Empty,
   Uploader,
   Stepper,
-  SubmitBar
+  SubmitBar,
+  Form,
+  GoodsAction,
+  GoodsActionButton,
+  GoodsActionIcon,
+  Steps,
+  Step,
 } from "vant";
 Vue.use(Button)
   .use(Icon)
@@ -101,7 +107,13 @@ Vue.use(Button)
   .use(Empty)
   .use(Uploader)
   .use(Stepper)
-  .use(SubmitBar);
+  .use(SubmitBar)
+  .use(Form)
+  .use(GoodsAction)
+  .use(GoodsActionButton)
+  .use(GoodsActionIcon)
+  .use(Steps)
+  .use(Step);
 
 Vue.config.productionTip = false;
 
@@ -143,6 +155,14 @@ VueAMap.initAMapApiLoader({
   v: "1.4.4",
 });
 
+Vue.mixin({
+  computed: {
+    selects() {
+      return store.state;
+    },
+  },
+});
+
 new Vue({
   store,
   router,

+ 3 - 1
src/router/index.js

@@ -4,6 +4,7 @@ import TeacherRouter from "./teacherRouter";
 import AppRouter from "./appRouter";
 import AuditionRouter from "./auditionRouter";
 import ServiceRouter from "./serviceRouter";
+import MessageRouter from "./messageRouter";
 
 Vue.use(Router);
 
@@ -134,7 +135,8 @@ defaultRouter = defaultRouter
   .concat(TeacherRouter)
   .concat(AppRouter)
   .concat(AuditionRouter)
-  .concat(ServiceRouter);
+  .concat(ServiceRouter)
+  .concat(MessageRouter);
 
 const router = new Router({
   // mode: 'history',

+ 10 - 10
src/router/teacherRouter.js

@@ -67,16 +67,16 @@ let teacherRouter = [
       weight: 1, // 页面权重
     },
   },
-  {
-    path: "/approval",
-    name: "approval",
-    component: () =>
-      import(/* webpackChunkName:'Approval'*/ "@/views/teacher/Approval.vue"),
-    meta: {
-      descrition: "需我审批",
-      weight: 2, // 页面权重
-    },
-  },
+  // {
+  //   path: "/approval",
+  //   name: "approval",
+  //   component: () =>
+  //     import(/* webpackChunkName:'Approval'*/ "@/views/teacher/Approval.vue"),
+  //   meta: {
+  //     descrition: "需我审批",
+  //     weight: 2, // 页面权重
+  //   },
+  // },
   {
     path: "/ccme",
     name: "ccme",

+ 65 - 13
src/store.js

@@ -1,22 +1,74 @@
-import Vue from 'vue'
-import Vuex from 'vuex'
-
-Vue.use(Vuex)
+import Vue from "vue";
+import Vuex from "vuex";
+import { queryAllOrgan } from "@/views/message/api";
+import { queryEmployeeOrgan } from "@/views/message/api";
+Vue.use(Vuex);
 
+const loadings = {};
+const filterOrganId = [
+  36, 39, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 52, 54, 55, 56,
+];
 export default new Vuex.Store({
   state: {
-    activeStudents:[], // 活动排课学生
-    activeCourse:{}, //活动排课
+    branchs: [],
+    allBranch: [],
+    activeStudents: [], // 活动排课学生
+    activeCourse: {}, //活动排课
   },
   mutations: {
-    commit_set_active_students:(state, students) => {
-      state.activeStudents = students
+    commit_branchs: (state, branchs) => {
+      state.branchs = branchs;
+    },
+    commit_all_branch: (state, allBranch) => {
+      state.allBranch = allBranch;
+    },
+    commit_set_active_students: (state, students) => {
+      state.activeStudents = students;
     },
     commit_set_active_course: (state, course) => {
-      state.activeCourse = course
-    }
+      state.activeCourse = course;
+    },
   },
   actions: {
-
-  }
-})
+    async setBranchs({ commit, state }, force) {
+      // console.log(state, state.branchs, force, loadings.commit_branchs, 'state')
+      if (
+        (!state.branchs.length || force === true) &&
+        !loadings.commit_branchs
+      ) {
+        loadings.commit_branchs = await queryEmployeeOrgan();
+        try {
+          const res = await loadings.commit_branchs;
+          commit("commit_branchs", res.data);
+        } catch (error) {
+          //
+        }
+        loadings.commit_branchs = false;
+      }
+    },
+    async setAllBranch({ commit, state }, force) {
+      if (
+        (!state.allBranch.length || force === true) &&
+        !loadings.commit_all_branch
+      ) {
+        const tenantId = sessionStorage.getItem("tenantId") || 1;
+        loadings.commit_all_branch = await queryAllOrgan({ tenantId });
+        try {
+          const res = await loadings.commit_all_branch;
+          const result = res.data;
+          let tempOrgan = [];
+          // 过滤不会显示的分部
+          result.forEach((item) => {
+            if (!filterOrganId.includes(item.key)) {
+              tempOrgan.push(item);
+            }
+          });
+          commit("commit_all_branch", tempOrgan);
+        } catch (error) {
+          //
+        }
+        loadings.commit_all_branch = false;
+      }
+    },
+  },
+});

+ 118 - 115
src/views/message/Approval.vue

@@ -1,134 +1,137 @@
 <template>
-    <div class="approval">
-        <van-sticky>
-            <!-- <m-header :isFixed="false" :isNative="false" :backUrl="backUrl" /> -->
-            <div class="user-container m-shadow">
-                <van-grid :column-num="3" :border="false">
-                    <van-grid-item text="需我审批" :badge="upcoming" @click="gotoMyApproval(1)">
-                        <template #icon><i class="icon icon1"></i></template>
-                    </van-grid-item>
-                    <van-grid-item text="我发起的" @click="gotoMyApproval(2)">
-                        <template #icon><i class="icon icon3"></i></template>
-                    </van-grid-item>
-                    <van-grid-item text="我相关的" @click="gotoMyApproval(3)">
-                        <template #icon><i class="icon icon2"></i></template>
-                    </van-grid-item>
-                </van-grid>
-            </div>
-        </van-sticky>
+  <div class="approval">
+    <van-sticky>
+      <!-- <m-header :isFixed="false" :isNative="false" :backUrl="backUrl" /> -->
+      <div class="user-container m-shadow">
+        <van-grid :column-num="3" :border="false">
+          <van-grid-item
+            text="需我审批"
+            :badge="upcoming"
+            @click="gotoMyApproval(1)"
+          >
+            <template #icon><i class="icon icon1"></i></template>
+          </van-grid-item>
+          <van-grid-item text="我发起的" @click="gotoMyApproval(2)">
+            <template #icon><i class="icon icon3"></i></template>
+          </van-grid-item>
+          <van-grid-item text="我相关的" @click="gotoMyApproval(3)">
+            <template #icon><i class="icon icon2"></i></template>
+          </van-grid-item>
+        </van-grid>
+      </div>
+    </van-sticky>
 
-        <apply-modal v-if="dataShow" :applyList="applyList" />
-        <m-empty v-else />
-    </div>
+    <apply-modal v-if="dataShow" :applyList="applyList" />
+    <m-empty v-else />
+  </div>
 </template>
 <script>
-import MHeader from '@/components/MHeader'
-import MEmpty from '@/components/MEmpty'
-import { classify, todoCount } from './api'
-import ApplyModal from './modal/applyModal'
+import MHeader from "@/components/MHeader";
+import MEmpty from "@/components/MEmpty";
+import { classify, todoCount } from "./api";
+import ApplyModal from "./modal/applyModal";
 export default {
-    name: 'approval',
-    components: { MHeader, ApplyModal, MEmpty },
-    data() {
-        return {
-            applyStatus: false,
-            applyList: [],
-            dataShow: true,
-            upcoming: null,
-            backUrl: {
-                status: true,
-                path: '/home'
-            },
-        }
+  name: "approval",
+  components: { MHeader, ApplyModal, MEmpty },
+  data() {
+    return {
+      applyStatus: false,
+      applyList: [],
+      dataShow: true,
+      upcoming: null,
+      backUrl: {
+        status: true,
+        path: "/home",
+      },
+    };
+  },
+  async mounted() {
+    document.title = "OA审批";
+    try {
+      const res = await todoCount();
+      // 我的待审批数
+      const result = res.data;
+      const upcoming = result > 0 ? result : null;
+      this.upcoming = upcoming && upcoming > 99 ? "99+" : upcoming;
+    } catch {
+      //
+    }
+    this.onApplyList();
+  },
+  methods: {
+    async onApplyList() {
+      try {
+        let res = await classify();
+        let tempList = res.data || [];
+        tempList.forEach((e) => {
+          e.process_list2 = [];
+          // 判断是否有子分类
+          if (e.process_list && e.process_list.length > 0) {
+            e.process_list.forEach((child) => {
+              // 父级分类
+              if (child.sub == 0) {
+                e.process_list2.push(child);
+              }
+            });
+          }
+        });
+        this.applyList = res.data;
+        this.dataShow = res.data.length > 0 ? true : false;
+      } catch {
+        //
+        this.dataShow = false;
+      }
+      this.applyStatus = true;
     },
-    async mounted(){
-        document.title = 'OA审批'
-        try {
-            const res = await todoCount()
-            // 我的待审批数
-            const result = res.data
-            const upcoming = result > 0 ?result : null
-            this.upcoming = upcoming && upcoming > 99 ? '99+' : upcoming
-        } catch {
-            //
-        }
-        this.onApplyList()
+    gotoMyApproval(val) {
+      this.$router.push({ path: "/myApproval", query: { classify: val } });
     },
-    methods: {
-        async onApplyList() {
-            try {
-                let res = await classify()
-                let tempList = res.data || []
-                tempList.forEach(e => {
-                    e.process_list2 = []
-                    // 判断是否有子分类
-                    if(e.process_list && e.process_list.length > 0) {
-                        e.process_list.forEach(child => {
-                            // 父级分类
-                            if(child.sub == 0) {
-                                e.process_list2.push(child)
-                            }
-                        })
-                    }
-                })
-                this.applyList = res.data
-                this.dataShow = res.data.length > 0 ? true : false
-            } catch {
-                //
-                this.dataShow = false
-            }
-            this.applyStatus = true
-        },
-        gotoMyApproval(val){
-            this.$router.push({path:"/myApproval",query:{classify:val}})
-        }
-    }
-}
+  },
+};
 </script>
-<style lang='less' scoped>
+<style lang="less" scoped>
 @import url("../../assets/commonLess/variable.less");
 /deep/.van-tab--active {
-    color: #EF5A50;
+  color: #ef5a50;
 }
 /deep/.van-tabs__line {
-    background-color: @mColor;
+  background-color: @mColor;
 }
 .approval {
-    min-height: 100vh;
+  min-height: 100vh;
 }
 .header_block {
-    // background: @mColor;
+  // background: @mColor;
 }
 .user-container {
-    background: @whiteColor;
-    padding: .05rem .08rem;
-    // margin: 0 .16rem .1rem;
-    margin-bottom: .1rem;
-    color: @tFontColor;
-    font-size: .14rem;
-    // border-radius: .05rem;
-    .item {
-        flex: 1;
-        color: #4F4F4F;
-        font-size: .14rem;
-    }
-    .icon {
-        display: inline-block;
-        width: .34rem;
-        height: .35rem;
-    }
-    .icon1 {
-        background: url('./images/a_1.png') no-repeat center;
-        background-size: contain;
-    }
-    .icon2 {
-        background: url('./images/a_2.png') no-repeat center;
-        background-size: contain;
-    }
-    .icon3 {
-        background: url('./images/a_3.png') no-repeat center;
-        background-size: contain;
-    }
+  background: @whiteColor;
+  padding: 0.05rem 0.08rem;
+  // margin: 0 .16rem .1rem;
+  margin-bottom: 0.1rem;
+  color: @tFontColor;
+  font-size: 0.14rem;
+  // border-radius: .05rem;
+  .item {
+    flex: 1;
+    color: #4f4f4f;
+    font-size: 0.14rem;
+  }
+  .icon {
+    display: inline-block;
+    width: 0.34rem;
+    height: 0.35rem;
+  }
+  .icon1 {
+    background: url("./images/a_1.png") no-repeat center;
+    background-size: contain;
+  }
+  .icon2 {
+    background: url("./images/a_2.png") no-repeat center;
+    background-size: contain;
+  }
+  .icon3 {
+    background: url("./images/a_3.png") no-repeat center;
+    background-size: contain;
+  }
 }
-
-</style>
+</style>

+ 2 - 0
src/views/message/ApprovalAction.vue

@@ -861,6 +861,8 @@ export default {
     .van-goods-action-icon__icon {
         font-size: 20px;
         min-width: 55px;
+        display: flex;
+        justify-content: center;
     }
     .van-goods-action-button--last {
         margin-right: .12rem;

+ 120 - 117
src/views/message/api.js

@@ -1,5 +1,5 @@
-import request from '@/helpers/request'
-const axios = require('@/common/axios').default
+import request from "@/helpers/request";
+const axios = require("@/common/axios").default;
 // 上传图片或文件
 // export function uploadFile(data) {
 //     return request({
@@ -10,185 +10,188 @@ const axios = require('@/common/axios').default
 //     })
 // }
 
-
 // 上传文件
 export const uploadFile = (data) => {
-    return axios({
-        url: '/api-web/uploadFile',
-        method: 'post',
-        data: data
-    })
-}
-
+  return axios({
+    url: "/api-web/uploadFile",
+    method: "post",
+    data: data,
+  });
+};
 
 // 上传文件
 export const oaUploadFile = (data) => {
-    return axios({
-        url: '/api-web/import/oaUploadFile',
-        method: 'post',
-        data: data
-    })
-}
+  return axios({
+    url: "/api-web/import/oaUploadFile",
+    method: "post",
+    data: data,
+  });
+};
 
 // 获取流程列表
 export function classify(data) {
-    return request({
-        baseURL: "/api-oa",
-        url: '/api/v1/process/classify',
-        method: 'get',
-        params: data
-    })
+  return request({
+    baseURL: "/api-oa",
+    url: "/api/v1/process/classify",
+    method: "get",
+    params: data,
+  });
 }
 
 // 获取我得待审批列表
 export function getWorkOrderList(data) {
-    return request({
-        baseURL: "/api-oa",
-        url: '/api/v1/work-order/list',
-        method: 'get',
-        hideLoading: true,
-        params: data
-    })
+  return request({
+    baseURL: "/api-oa",
+    url: "/api/v1/work-order/list",
+    method: "get",
+    hideLoading: true,
+    params: data,
+  });
 }
 
 export function processStructure(data) {
-    return request({
-        baseURL: "/api-oa",
-        url: '/api/v1/work-order/process-structure',
-        method: 'get',
-        params: data
-    })
+  return request({
+    baseURL: "/api-oa",
+    url: "/api/v1/work-order/process-structure",
+    method: "get",
+    params: data,
+  });
 }
 
 // 新建工单
 export function createWorkOrder(data) {
-    return request({
-        baseURL: "/api-oa",
-        noClean: true,
-        url: '/api/v1/work-order/create',
-        method: 'post',
-        data
-    })
+  return request({
+    baseURL: "/api-oa",
+    noClean: true,
+    url: "/api/v1/work-order/create",
+    method: "post",
+    data,
+  });
 }
 
 // 处理工单
 export function handleWorkOrder(data) {
-    return request({
-        baseURL: "/api-oa",
-        noClean: true,
-        url: '/api/v1/work-order/handle',
-        method: 'post',
-        data
-    })
+  return request({
+    baseURL: "/api-oa",
+    noClean: true,
+    url: "/api/v1/work-order/handle",
+    method: "post",
+    data,
+  });
 }
 
 // 获取学校
 export function getOrganCooperation(data) {
-    return request({
-        url: '/eduOrganization/getOrganCooperation',
-        method: 'get',
-        params: data
-    })
+  return request({
+    url: "/cooperation/getOrganCooperation",
+    method: "get",
+    params: data,
+  });
 }
 
 export function sysUserList(data) {
-    return request({
-        baseURL: "/api-oa",
-        noClean: true,
-        url: '/api/v1/sysUserList',
-        method: 'get',
-        params: data
-    })
+  return request({
+    baseURL: "/api-oa",
+    noClean: true,
+    url: "/api/v1/sysUserList",
+    method: "get",
+    params: data,
+  });
 }
 
 // 转交工单
 export function inversionWorkOrder(data) {
-    return request({
-        baseURL: "/api-oa",
-        url: '/api/v1/work-order/inversion',
-        method: 'post',
-        data
-    })
+  return request({
+    baseURL: "/api-oa",
+    url: "/api/v1/work-order/inversion",
+    method: "post",
+    data,
+  });
 }
 
 // 催办工单
 export function urgeWorkOrder(params) {
-    return request({
-        baseURL: '/api-oa',
-        url: '/api/v1/work-order/urge',
-        method: 'get',
-        params
-    })
+  return request({
+    baseURL: "/api-oa",
+    url: "/api/v1/work-order/urge",
+    method: "get",
+    params,
+  });
 }
 
 export function getInfo() {
-    return request({
-        baseURL: '/api-oa',
-        url: '/api/v1/getinfo',
-        method: 'get'
-    })
+  return request({
+    baseURL: "/api-oa",
+    url: "/api/v1/getinfo",
+    method: "get",
+  });
 }
 
 export function dashboard() {
-    return request({
-        baseURL: '/api-oa',
-        url: '/api/v1/dashboard',
-        method: 'get'
-    })
+  return request({
+    baseURL: "/api-oa",
+    url: "/api/v1/dashboard",
+    method: "get",
+  });
 }
 
 export function todoCount() {
-    return request({
-        baseURL: '/api-oa',
-        url: '/api/v1/dashboard/todoCount',
-        method: 'get'
-    })
+  return request({
+    baseURL: "/api-oa",
+    url: "/api/v1/dashboard/todoCount",
+    method: "get",
+  });
 }
 
-
-
 // 结束工单
 export function unityWorkOrder(params) {
-    return request({
-        baseURL: '/api-oa',
-        url: '/api/v1/work-order/unity',
-        method: 'get',
-        params
-    })
+  return request({
+    baseURL: "/api-oa",
+    url: "/api/v1/work-order/unity",
+    method: "get",
+    params,
+  });
 }
 
-
 // 全部分部
 export function queryAllOrgan(params) {
-    return request({
-        url: '/eduOrganization/queryAllOrgan',
-        method: 'get',
-        params
-    })
+  return request({
+    url: "/teacher/queryOrganList",
+    method: "get",
+    params,
+  });
+}
+
+export function queryEmployeeOrgan(data) {
+  return request({
+    url: "/eduOrganization/queryEmployeeOrgan",
+    method: "get",
+    params: data,
+  });
 }
 
 //
 export function asyncPlayLog(data) {
-    return request({
-        url: '/oa/syncPayLog',
-        method: 'post',
-        requestType: 'form',
-        data
-    })
+  return request({
+    url: "/oa/syncPayLog",
+    method: "post",
+    requestType: "form",
+    data,
+  });
 }
 
 export function checkCourseReturnFee(data) {
-    return request({
-        url: '/oa/checkCourseReturnFee',
-        method: 'post',
-        data
-    })
+  return request({
+    url: "/oa/checkCourseReturnFee",
+    method: "post",
+    data,
+  });
 }
 
 // /sysMessage/queryCountOfUnread
 export function queryCountOfUnread() {
-    return request({
-        url: '/sysEduMessage/queryCountOfUnread',
-        method: 'get'
-    })
+  return request({
+    url: "/sysEduMessage/queryCountOfUnread",
+    method: "get",
+  });
 }

+ 39 - 39
src/views/message/control/controlCommon.less

@@ -1,40 +1,40 @@
-.controller {
-    .preview {
-        padding: 12px 16px 5px;
-        line-height: 1.3;
-        display: flex;
-        flex-direction: column;
-        font-size: 14px;
-        /deep/.van-cell__title {
-            margin-bottom: 7px;
-            width: auto;
-            color: #808080;
-        }
-        /deep/.van-cell__value {
-            text-align: left;
-            color: #1a1a1a;
-            font-size: 16px;
-        }
-    }
-
-    /deep/.van-field {
-        padding: 12px 16px;
-        line-height: 1.3;
-        display: flex;
-        flex-direction: column;
-        font-size: 16px;
-    }
-    /deep/.van-field__label {
-        margin-bottom: 7px;
-        width: auto;
-        color: #111F2C;
-        font-size: 14px;
-    }
-    /deep/.van-field__value {
-        padding: .03rem 0;
-    }
-}
-
-.o-unit {
-    margin-bottom: 12px;
+.controller {
+    .preview {
+        padding: 12px 16px 5px;
+        line-height: 1.3;
+        display: flex;
+        flex-direction: column;
+        font-size: 14px;
+        /deep/.van-cell__title {
+            margin-bottom: 7px;
+            width: auto;
+            color: #808080;
+        }
+        /deep/.van-cell__value {
+            text-align: left;
+            color: #1a1a1a;
+            font-size: 16px;
+        }
+    }
+
+    /deep/.van-field {
+        padding: 12px 16px;
+        line-height: 1.3;
+        display: flex;
+        flex-direction: column;
+        font-size: 16px;
+    }
+    /deep/.van-field__label {
+        margin-bottom: 7px;
+        width: auto;
+        color: #111F2C;
+        font-size: 14px;
+    }
+    /deep/.van-field__value {
+        padding: .03rem 0;
+    }
+}
+
+.o-unit {
+    margin-bottom: 12px;
 }

+ 39 - 39
src/views/message/control/divider.vue

@@ -1,40 +1,40 @@
-<template>
-    <div class="oDivider" :class="[preview ? '' : 'o-unit']" v-if="widget.type == 'divider'">
-        <van-divider
-            :style="{ borderColor: '#c0c0c0', padding: '0 16px', margin: 0 }"
-            v-if="!preview"
-            :content-position="options.content_position">{{ dataModel }}</van-divider>
-        <van-divider
-            :style="{ borderColor: '#c0c0c0', margin: 0 }"
-            v-else
-            :content-position="options.content_position">{{ dataModel }}</van-divider>
-    </div>
-</template>
-<script>
-
-export default {
-    name: 'oDivider',
-    props: ['widget', 'preview'],
-    data() {
-        return {
-            dataModel: this.widget.options?.defaultValue || null,
-        }
-    },
-    mounted() {
-        // 初始化参数
-    },
-    methods: {
-    },
-    computed: {
-        options() {
-            return this.widget.options || {}
-        },
-    }
-}
-</script>
-
-<style lang='less' scoped>
-.o-unit {
-    margin-bottom: 12px;
-}
+<template>
+    <div class="oDivider" :class="[preview ? '' : 'o-unit']" v-if="widget.type == 'divider'">
+        <van-divider
+            :style="{ borderColor: '#c0c0c0', padding: '0 16px', margin: 0 }"
+            v-if="!preview"
+            :content-position="options.content_position">{{ dataModel }}</van-divider>
+        <van-divider
+            :style="{ borderColor: '#c0c0c0', margin: 0 }"
+            v-else
+            :content-position="options.content_position">{{ dataModel }}</van-divider>
+    </div>
+</template>
+<script>
+
+export default {
+    name: 'oDivider',
+    props: ['widget', 'preview'],
+    data() {
+        return {
+            dataModel: this.widget.options?.defaultValue || null,
+        }
+    },
+    mounted() {
+        // 初始化参数
+    },
+    methods: {
+    },
+    computed: {
+        options() {
+            return this.widget.options || {}
+        },
+    }
+}
+</script>
+
+<style lang='less' scoped>
+.o-unit {
+    margin-bottom: 12px;
+}
 </style>

+ 327 - 286
src/views/message/control/fileUpload.vue

@@ -1,50 +1,78 @@
 <template>
-    <div class="oFileUpload controller" :class="[preview ? '' : 'o-unit']" v-if="widget.type == 'file'">
-        <van-field
-            :name="widget.model"
-            :label="widget.name || '附件'"
-            :required="fileCheck ? false : options.required || false"
-            :rules="rule"
-            v-if="!preview"
+  <div
+    class="oFileUpload controller"
+    :class="[preview ? '' : 'o-unit']"
+    v-if="widget.type == 'file'"
+  >
+    <van-field
+      :name="widget.model"
+      :label="widget.name || '附件'"
+      :required="fileCheck ? false : options.required || false"
+      :rules="rule"
+      v-if="!preview"
+    >
+      <template #input>
+        <!-- image/*, *.xlsx, *.xls, application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document, *.txt, *.pdf -->
+        <van-uploader
+          v-model="dataModel"
+          :before-read="beforeRead"
+          :before-delete="beforeDelete"
+          :after-read="afterRead"
+          :disabled="options.disabled || false"
+          :max-count="options.length"
+          accept="image/*, *.xlsx, *.xls,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel, application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document, *.txt, *.pdf"
+          preview-size="0.6rem"
         >
-            <template #input>
-                <!-- image/*, *.xlsx, *.xls, application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document, *.txt, *.pdf -->
-                <van-uploader
-                    v-model="dataModel"
-                    :before-read="beforeRead"
-                    :before-delete="beforeDelete"
-                    :after-read="afterRead"
-                    :disabled="options.disabled || false"
-                    :max-count="options.length"
-                    accept="image/*, *.xlsx, *.xls,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel, application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document, *.txt, *.pdf"
-                    preview-size="0.6rem">
-                    <!-- <template v-slot:preview-cover="props">
+          <!-- <template v-slot:preview-cover="props">
                         {{ props }}
                     </template> -->
-                    <!-- <template #preview-cover>
+          <!-- <template #preview-cover>
                         2323
                     </template> -->
-                </van-uploader>
-            </template>
-        </van-field>
-        <van-field
-            v-else
-            :name="widget.model"
-            :label="widget.name || '附件'"
-            class="preview"
+        </van-uploader>
+      </template>
+    </van-field>
+    <van-field
+      v-else
+      :name="widget.model"
+      :label="widget.name || '附件'"
+      class="preview"
+    >
+      <template #input>
+        <div
+          class="preview_file"
+          v-for="(item, index) in dataModel"
+          :key="index"
         >
-            <template #input>
-                <div class="preview_file" v-for="(item, index) in dataModel" :key="index">
-                    <div class="preview_item">
-                        <i class="van-icon van-icon-description van-uploader__file-icon"></i>
-                        <span style="white-space: nowrap;overflow: hidden;text-overflow: ellipsis;width: 2rem;">{{ item.name || item.url }}</span>
-                    </div>
-                    <div class="preview_btn">
-                        <van-button @click="downLoadFile2(item.url)" type="info" size="mini">下载</van-button>
-                        <van-button :disabled="!checkFileSuffix(item.url)" v-if="checkFileSuffix(item.url)" @click="downLoadFile(item.url)" type="info" size="mini">预览</van-button>
-                    </div>
-                </div>
-                <!-- <div class="van-uploader__preview" v-for="(item, index) in dataModel" :key="index">
+          <div class="preview_item">
+            <i
+              class="van-icon van-icon-description van-uploader__file-icon"
+            ></i>
+            <span
+              style="
+                white-space: nowrap;
+                overflow: hidden;
+                text-overflow: ellipsis;
+                width: 2rem;
+              "
+              >{{ item.name || item.url }}</span
+            >
+          </div>
+          <div class="preview_btn">
+            <van-button @click="downLoadFile2(item.url)" type="info" size="mini"
+              >下载</van-button
+            >
+            <van-button
+              :disabled="!checkFileSuffix(item.url)"
+              v-if="checkFileSuffix(item.url)"
+              @click="downLoadFile(item.url)"
+              type="info"
+              size="mini"
+              >预览</van-button
+            >
+          </div>
+        </div>
+        <!-- <div class="van-uploader__preview" v-for="(item, index) in dataModel" :key="index">
                     <div class="van-uploader__file" style="width: 0.6rem; height: 0.6rem;" >
                         <i class="van-icon van-icon-description van-uploader__file-icon"></i>
                         <div class="van-uploader__file-name van-ellipsis">
@@ -56,269 +84,282 @@
                         <van-button :disabled="!checkFileSuffix(item.url)" @click="downLoadFile(item.url)" type="info" size="mini">预览</van-button>
                     </div>
                 </div> -->
-            </template>
-        </van-field>
+      </template>
+    </van-field>
 
-        <van-popup position="bottom" v-model="filePreview" style="height: 100%;border-radius: 0;">
-            <van-sticky>
-                <m-header :backUrl="backUrl" :isFixed="false" name="预览" />
-            </van-sticky>
-            <div id="previewIframe" style="height: calc(100vh - 0.44rem);" v-if="filePreview && (fileType == 'xls' || fileType == 'pdf')">
-            </div>
-            <div style="height: calc(100vh - 0.44rem);" v-if="filePreview && fileType == 'doc'">
-            </div>
-            <!-- <div ref="pdf" style="height: calc(100vh - 0.44rem);" v-if="filePreview && fileType == 'pdf'">
+    <van-popup position="bottom" v-model="filePreview" style="height: 100%">
+      <van-sticky>
+        <m-header :backUrl="backUrl" :isFixed="false" name="预览" />
+      </van-sticky>
+      <div
+        id="previewIframe"
+        style="height: calc(100vh - 0.44rem)"
+        v-if="filePreview && (fileType == 'xls' || fileType == 'pdf')"
+      ></div>
+      <div
+        style="height: calc(100vh - 0.44rem)"
+        v-if="filePreview && fileType == 'doc'"
+      ></div>
+      <!-- <div ref="pdf" style="height: calc(100vh - 0.44rem);" v-if="filePreview && fileType == 'pdf'">
             </div> -->
-        </van-popup>
-    </div>
+    </van-popup>
+  </div>
 </template>
 <script>
-import MHeader from '@/components/MHeader'
-import setLoading from '@/common/loading'
-import { uploadFile, oaUploadFile } from '@/views/message/api'
-import { browser } from '@/common/common'
-import { postMessage } from '@/helpers/native-message'
+import MHeader from "@/components/MHeader";
+import setLoading from "@/common/loading";
+import { uploadFile, oaUploadFile } from "../api";
+import { browser } from "@/common/util";
+import { postMessage } from "@/helpers/native-message";
 export default {
-    name: 'oFileUpload',
-    components: { MHeader },
-    props: ['widget', 'preview', 'value', 'fileCheck'],
-    data() {
-        // xls, doc, pdf
-        return {
-            dataModel: this.widget.options?.defaultValue || null,
-            filePreview: false,
-            fileType: 'xls',
-            previewUrl: '',
-            numPages: 1,
-            backUrl: {
-                status: true,
-                callBack: () => {
-                    this.filePreview = false;
-                },
-            },
+  name: "oFileUpload",
+  components: { MHeader },
+  props: ["widget", "preview", "value", "fileCheck"],
+  data() {
+    // xls, doc, pdf
+    return {
+      dataModel: this.widget.options?.defaultValue || null,
+      filePreview: false,
+      fileType: "xls",
+      previewUrl: "",
+      numPages: 1,
+      backUrl: {
+        status: true,
+        callBack: () => {
+          this.filePreview = false;
+        },
+      },
+    };
+  },
+  mounted() {
+    // 初始化参数
+    if (this.value) {
+      const widget = this.widget;
+      const model = widget.originModel || widget.model;
+      for (let v in this.value) {
+        if (v == model) {
+          this.dataModel = this.value[v];
         }
+      }
+    }
+  },
+  methods: {
+    checkFileSuffix(url) {
+      let urlArr = url.split(".");
+      let suffix = urlArr[urlArr.length - 1];
+      //  || suffix == 'doc' || suffix == 'docx'
+      if (suffix == "xlsx" || suffix == "xls" || suffix == "pdf") {
+        return true;
+      } else {
+        return false;
+      }
     },
-    mounted() {
-        // 初始化参数
-        if(this.value) {
-            const widget = this.widget
-            const model = widget.originModel || widget.model
-            for(let v in this.value) {
-                if(v == model) {
-                    this.dataModel = this.value[v]
-                }
-            }
+    getFileSuffix(url) {
+      let urlArr = url.split(".");
+      let suffix = urlArr[urlArr.length - 1];
+      if (suffix == "xlsx" || suffix == "xls") {
+        return "xls";
+      } else if (suffix == "doc" || suffix == "docx") {
+        return "doc";
+      } else if (suffix == "pdf") {
+        return "pdf";
+      } else {
+        return "";
+      }
+    },
+    beforeRead(file) {
+      const isLt2M = file.size / 1024 / 1024 < 20;
+      if (!isLt2M) {
+        this.$toast("上传文件大小不能超过 20MB");
+        return false;
+      }
+      return true;
+    },
+    beforeDelete(file, detail) {
+      this.dataModel.splice(detail.index, 1);
+      if (!this.dataModel || (this.dataModel && this.dataModel.length <= 0)) {
+        this.$emit("fileCheckRequired", false);
+      }
+      return true;
+    },
+    async afterRead(file, detail) {
+      // 上传头像
+      try {
+        setLoading(true);
+        file.status = "uploading";
+        file.message = "上传中...";
+        let formData = new FormData();
+        formData.append("file", file.file);
+        let res = null;
+        const query = this.$route.query;
+        if (query.processId) {
+          formData.append("processId", query.processId);
+          res = await oaUploadFile(formData);
+        } else {
+          res = await uploadFile(formData);
         }
+        let result = res.data;
+        if (result.code == 200) {
+          file.status = "done";
+          this.dataModel[detail.index] = {
+            url: result.data.url,
+            name: file.file.name,
+            file: {
+              name: file.file.name,
+            },
+          };
+          // 目前只对 退费模板做处理(id: 19)
+          if (query.processId == 19) {
+            this.$emit("fileCheckRequired", true);
+          }
+        } else {
+          file.status = "failed";
+          file.message = "上传失败";
+          this.$toast(result.msg);
+          this.dataModel.splice(detail.index, 1);
+          return false;
+        }
+        setLoading(false);
+      } catch (err) {
+        setLoading(false);
+        file.status = "failed";
+        file.message = "上传失败";
+        this.dataModel.splice(detail.index, 1);
+        return false;
+      }
     },
-    methods: {
-        checkFileSuffix(url) {
-            let urlArr = url.split('.')
-            let suffix = urlArr[urlArr.length-1]
-            //  || suffix == 'doc' || suffix == 'docx'
-            if(suffix == 'xlsx' || suffix == 'xls' || suffix == 'pdf') {
-                return true
-            } else {
-                return false
-            }
-        },
-        getFileSuffix(url) {
-            let urlArr = url.split('.')
-            let suffix = urlArr[urlArr.length-1]
-            if(suffix == 'xlsx' || suffix == 'xls') {
-                return 'xls'
-            } else if(suffix == 'doc' || suffix == 'docx') {
-                return 'doc'
-            } else if(suffix == 'pdf') {
-                return 'pdf'
-            } else {
-                return ''
-            }
-        },
-        beforeRead(file) {
-            const isLt2M = file.size / 1024 / 1024 < 5
-            if (!isLt2M) {
-                this.$toast('上传文件大小不能超过 5MB')
-                return false
-            }
-            return true
-        },
-        beforeDelete(file, detail) {
-            this.dataModel.splice(detail.index, 1)
-            if(!this.dataModel || this.dataModel && this.dataModel.length <= 0) {
-                this.$emit('fileCheckRequired', false)
-            }
-            return true
-        },
-        async afterRead(file, detail) { // 上传头像
-            try {
-                setLoading(true)
-                file.status = 'uploading'
-                file.message = '上传中...'
-                let formData = new FormData()
-                formData.append('file', file.file)
-                let res = null
-                const query = this.$route.query
-                if(query.processId) {
-                    formData.append('processId', query.processId)
-                    res = await oaUploadFile(formData)
-                } else {
-                    res = await uploadFile(formData)
-                }
-                let result = res.data
-                if(result.code == 200) {
-                    file.status = 'done'
-                    this.dataModel[detail.index] = {
-                        url: result.data.url,
-                        name: file.file.name,
-                        file: {
-                            name: file.file.name
-                        }
-                    }
-                    // 目前只对 退费模板做处理(id: 19)
-                    if(query.processId == 19) {
-                        this.$emit('fileCheckRequired', true)
-                    }
-                } else {
-                    file.status = 'failed'
-                    file.message = '上传失败'
-                    this.$toast(result.msg)
-                    this.dataModel.splice(detail.index, 1)
-                    return false
-                }
-                setLoading(false)
-            } catch (err) {
-                setLoading(false)
-                file.status = 'failed'
-                file.message = '上传失败'
-                this.dataModel.splice(detail.index, 1)
-                return false
-            }
-        },
-        downLoadFile2(file) {
-            this.$toast.loading({
-                duration: 0, // 持续展示 toast
-                forbidClick: true,
-                message: '下载中...',
-            })
-            if(browser().isApp) {
-                postMessage({ api: 'downloadFile', content: { downloadUrl: file } }, () => {
-                    this.$toast.clear()
-                })
+    downLoadFile2(file) {
+      this.$toast.loading({
+        duration: 0, // 持续展示 toast
+        forbidClick: true,
+        message: "下载中...",
+      });
+      if (browser().isApp) {
+        postMessage(
+          { api: "downloadFile", content: { downloadUrl: file } },
+          () => {
+            this.$toast.clear();
+          }
+        );
+      } else {
+        this.$toast.clear();
+        window.location.href = file;
+      }
+    },
+    downLoadFile(file) {
+      // this.previewUrl = 'https://view.officeapps.live.com/op/view.aspx?src=' + file
+      this.filePreview = true;
+      this.fileType = this.getFileSuffix(file);
+
+      if (this.fileType == "xls" || this.fileType == "pdf") {
+        this.$toast.loading({
+          duration: 0, // 持续展示 toast
+          forbidClick: true,
+          message: "加载中...",
+        });
+        let _this = this;
+        this.$nextTick(() => {
+          let iframe = document.createElement("iframe");
+          iframe.id = "preview_iframe";
+          iframe.style.width = "100%";
+          iframe.style.height = "100%";
+          iframe.style.border = "none";
+          if (this.fileType == "xls") {
+            if (browser().android) {
+              iframe.src =
+                "https://api.idocv.com/view/url?url=" +
+                encodeURIComponent(file + "?times=" + new Date().getTime());
             } else {
-                this.$toast.clear()
-                window.location.href = file
+              iframe.src =
+                "https://view.officeapps.live.com/op/view.aspx?src=" + file;
             }
-        },
-        downLoadFile(file) {
-            // this.previewUrl = 'https://view.officeapps.live.com/op/view.aspx?src=' + file
-            this.filePreview = true
-            this.fileType = this.getFileSuffix(file)
+          } else {
+            iframe.src =
+              window.location.origin +
+              "/pdf/web/viewer.html?file=" +
+              encodeURIComponent(file);
+          }
+          if (iframe.attachEvent) {
+            iframe.attachEvent("onload", function () {
+              _this.$toast.clear();
+            });
+          } else {
+            iframe.onload = function () {
+              _this.$toast.clear();
 
-            if(this.fileType == 'xls' || this.fileType == 'pdf') {
-                this.$toast.loading({
-                    duration: 0, // 持续展示 toast
-                    forbidClick: true,
-                    message: '加载中...',
-                })
-                let _this = this
-                this.$nextTick(() => {
-                    let iframe = document.createElement("iframe");
-                    iframe.id = 'preview_iframe'
-                    iframe.style.width = '100%';
-                    iframe.style.height = '100%';
-                    iframe.style.border = 'none';
-                    if(this.fileType == 'xls') {
-                        if(browser().android) {
-                            iframe.src = 'https://api.idocv.com/view/url?url=' + encodeURIComponent(file + '?times=' + new Date().getTime())
-                        } else {
-                            iframe.src = 'https://view.officeapps.live.com/op/view.aspx?src=' + file
-                        }
-                    } else {
-                        iframe.src = window.location.origin + '/pdf/web/viewer.html?file=' + encodeURIComponent(file)
-                    }
-                    if (iframe.attachEvent){
-                        iframe.attachEvent("onload", function(){
-                            _this.$toast.clear()
-                        });
-                    } else {
-                        iframe.onload = function(){
-                            _this.$toast.clear()
-
-                            // setTimeout(() => {
-                            //     let dom =  document.querySelector('#preview_iframe').contentWindow.document
-                            //     let scripts = dom.querySelectorAll('script[src]')
-                            //     if(scripts)
-                            // }, 2000);
-                        };
-                    }
-                    document.querySelector('#previewIframe').appendChild(iframe);
-                })
-            } else if(this.fileType == 'doc') {
-            //     // this.previewUrl = 'https://view.officeapps.live.com/op/view.aspx?src=' + file
-
-            }
-        },
+              // setTimeout(() => {
+              //     let dom =  document.querySelector('#preview_iframe').contentWindow.document
+              //     let scripts = dom.querySelectorAll('script[src]')
+              //     if(scripts)
+              // }, 2000);
+            };
+          }
+          document.querySelector("#previewIframe").appendChild(iframe);
+        });
+      } else if (this.fileType == "doc") {
+        //     // this.previewUrl = 'https://view.officeapps.live.com/op/view.aspx?src=' + file
+      }
     },
-    computed: {
-        options() {
-            return this.widget.options || {}
-        },
-        rule() {
-            let rules = this.widget.rules || []
-            if(rules && rules.length > 0) {
-                rules.forEach(item => {
-                    if(item.pattern) {
-                        item.pattern = eval(item.pattern)
-                    }
-                    // 判断是否上传文件
-                    if(this.fileCheck) {
-                        item.required = false
-                    }
-                });
-            }
-            return rules
-        }
+  },
+  computed: {
+    options() {
+      return this.widget.options || {};
     },
-    watch: {
-        // dataModel: {
-        //     deep: true,
-        //     handler(newValue) {
-        //         if (newValue !== undefined && newValue !== null) {
-        //         }
-        //     }
-        // },
-    }
-}
+    rule() {
+      let rules = this.widget.rules || [];
+      if (rules && rules.length > 0) {
+        rules.forEach((item) => {
+          if (item.pattern) {
+            item.pattern = eval(item.pattern);
+          }
+          // 判断是否上传文件
+          if (this.fileCheck) {
+            item.required = false;
+          }
+        });
+      }
+      return rules;
+    },
+  },
+  watch: {
+    // dataModel: {
+    //     deep: true,
+    //     handler(newValue) {
+    //         if (newValue !== undefined && newValue !== null) {
+    //         }
+    //     }
+    // },
+  },
+};
 </script>
 
-<style lang='less' scoped>
-@import url('./controlCommon.less');
+<style lang="less" scoped>
+@import url("./controlCommon.less");
 .oFileUpload {
-    /deep/.van-uploader__wrapper--disabled {
-        opacity: 0.9;
-    }
-    /deep/.van-field__control--custom {
-        flex-wrap: wrap;
-    }
+  /deep/.van-uploader__wrapper--disabled {
+    opacity: 0.9;
+  }
+  /deep/.van-field__control--custom {
+    flex-wrap: wrap;
+  }
 
-    .preview_file {
-        width: 100%;
-        font-size: 14px;
-        display: flex;
-        justify-content: space-between;
-        background: #f7f7f7;
-        padding: .08rem;
-        margin-bottom: 0.08rem;
-        .preview_item {
-            display: flex;
-            padding-top: .03rem;
-            flex-basis: 70%;
-        }
-        .preview_btn {
-            text-align: right;
-            flex-basis: 30%;
-        }
+  .preview_file {
+    width: 100%;
+    font-size: 14px;
+    display: flex;
+    justify-content: space-between;
+    background: #f7f7f7;
+    padding: 0.08rem;
+    margin-bottom: 0.08rem;
+    .preview_item {
+      display: flex;
+      padding-top: 0.03rem;
+      flex-basis: 70%;
     }
+    .preview_btn {
+      text-align: right;
+      flex-basis: 30%;
+    }
+  }
 }
-
-</style>
+</style>

+ 165 - 123
src/views/message/control/imgFile.vue

@@ -1,139 +1,181 @@
 <template>
-    <div class="oImgUpload controller" :class="[preview ? '' : 'o-unit']" v-if="widget.type == 'imgupload'">
-        <van-field
-            :name="widget.model"
-            :label="widget.name || '图片'"
-            :required="fileCheck ? false : options.required || false"
-            :rules="rule"
-            v-if="!preview"
+  <div
+    class="oImgUpload controller"
+    :class="[preview ? '' : 'o-unit']"
+    v-if="widget.type == 'imgupload'"
+  >
+    <van-field
+      :name="widget.model"
+      :label="widget.name || '图片'"
+      :required="fileCheck ? false : options.required || false"
+      :rules="rule"
+      v-if="!preview"
+    >
+      <template #input>
+        <van-uploader
+          v-model="dataModel"
+          :before-read="beforeRead"
+          :before-delete="beforeDelete"
+          :after-read="afterRead"
+          :max-count="options.length"
+          preview-size="0.6rem"
         >
-            <template #input>
-                <van-uploader
-                    v-model="dataModel"
-                    :before-read="beforeRead"
-                    :before-delete="beforeDelete"
-                    :after-read="afterRead"
-                    :max-count="options.length"
-                    preview-size="0.6rem">
-                </van-uploader>
-            </template>
-        </van-field>
-        <van-field
-            v-else
-            :name="widget.model"
-            :label="widget.name || '图片'"
-            class="preview"
+        </van-uploader>
+      </template>
+    </van-field>
+    <van-field
+      v-else
+      :name="widget.model"
+      :label="widget.name || '图片'"
+      class="preview"
+    >
+      <template #input>
+        <van-uploader
+          v-model="dataModel"
+          :disabled="true"
+          :deletable="false"
+          :max-count="dataModel.length || 0"
+          preview-size="0.5rem"
         >
-            <template #input>
-                <van-uploader
-                    v-model="dataModel"
-                    :disabled="true"
-                    :deletable="false"
-                    :max-count="dataModel.length || 0"
-                    preview-size="0.5rem">
-                </van-uploader>
-            </template>
-        </van-field>
-    </div>
+        </van-uploader>
+      </template>
+    </van-field>
+  </div>
 </template>
 <script>
-import setLoading from '@/common/loading'
-import { uploadFile } from '@/views/message/api'
+// import setLoading from "@/common/loading";
+// import { uploadFile } from "@/api/service";
+import { policy } from "@/views/massMessage/api";
+import axios from "axios";
 export default {
-    name: 'oImgUpload',
-    props: ['widget', 'preview', 'value', 'fileCheck'],
-    data() {
-        return {
-            dataModel: this.widget.options?.defaultValue || [],
+  name: "oImgUpload",
+  props: ["widget", "preview", "value", "fileCheck"],
+  data() {
+    return {
+      dataModel: this.widget.options?.defaultValue || [],
+      ossUploadUrl: "https://ks3-cn-beijing.ksyuncs.com/daya",
+      dataObj: {
+        policy: "",
+        signature: "",
+        key: "",
+        KSSAccessKeyId: "",
+        acl: "public-read",
+        name: "",
+      },
+    };
+  },
+  mounted() {
+    // 初始化参数
+    if (this.value) {
+      const widget = this.widget;
+      const model = widget.originModel || widget.model;
+      for (let v in this.value) {
+        if (v == model) {
+          this.dataModel = this.value[v];
         }
+      }
+    }
+  },
+  methods: {
+    beforeRead(file) {
+      const isLt2M = file.size / 1024 / 1024 < 5;
+      if (!isLt2M) {
+        this.$toast("上传图片大小不能超过 5MB");
+        return false;
+      }
+      return true;
+    },
+    beforeDelete(file, detail) {
+      this.dataModel.splice(detail.index, 1);
+      return true;
     },
-    mounted() {
-        // 初始化参数
-        if(this.value) {
-            const widget = this.widget
-            const model = widget.originModel || widget.model
-            for(let v in this.value) {
-                if(v == model) {
-                    this.dataModel = this.value[v]
-                }
-            }
+    async afterRead(file, detail) {
+      // 上传头像
+      try {
+        file.status = "uploading";
+        file.message = "上传中...";
+        let tempName = file.file.name || "";
+        const fileName = tempName && tempName.replace(/ /gi, "_");
+        let key = new Date().getTime() + fileName;
+        let objTemp = {
+          filename: fileName,
+          bucketName: this.bucket_name,
+          postData: {
+            filename: fileName,
+            acl: "public-read",
+            key: key,
+            unknowValueField: [],
+          },
+        };
+
+        const res = await policy(objTemp);
+        const obj = {
+          policy: res.data.policy,
+          signature: res.data.signature,
+          key: key,
+          KSSAccessKeyId: res.data.kssAccessKeyId,
+          acl: "public-read",
+          name: fileName,
+        };
+
+        let formData = new FormData();
+        for (let key in obj) {
+          formData.append(key, obj[key]);
         }
+        formData.append("file", file.file);
+        await axios({
+          method: "post",
+          url: this.ossUploadUrl,
+          data: formData,
+        });
+        const uploadUrl = this.ossUploadUrl + "/" + key;
+        file.status = "done";
+        this.dataModel[detail.index] = {
+          url: uploadUrl,
+        };
+      } catch (e) {
+        //
+        file.status = "failed";
+        file.message = "上传失败";
+        return false;
+      }
     },
-    methods: {
-        beforeRead(file) {
-            const isLt2M = file.size / 1024 / 1024 < 5
-            if (!isLt2M) {
-                this.$toast('上传图片大小不能超过 5MB')
-                return false
-            }
-            return true
-        },
-        beforeDelete(file, detail) {
-            this.dataModel.splice(detail.index, 1)
-            return true
-        },
-        async afterRead(file, detail) { // 上传头像
-            try {
-                setLoading(true)
-                file.status = 'uploading'
-                file.message = '上传中...'
-                let formData = new FormData()
-                formData.append('file', file.file)
-                let res = await uploadFile(formData)
-                let result = res.data
-                if(result.code == 200) {
-                    file.status = 'done'
-                    this.dataModel[detail.index] = {
-                        url: result.data.url
-                    }
-                } else {
-                    file.status = 'failed'
-                    file.message = '上传失败'
-                    this.$toast(result.msg)
-                    return false
-                }
-                setLoading(false)
-            } catch (err) {
-                setLoading(false)
-                return false
-            }
-        },
+  },
+  computed: {
+    options() {
+      return this.widget.options || {};
     },
-    computed: {
-        options() {
-            return this.widget.options || {}
-        },
-        rule() {
-            let rules = this.widget.rules || []
-            if(rules && rules.length > 0) {
-                rules.forEach(item => {
-                    if(item.pattern) {
-                        item.pattern = eval(item.pattern)
-                    }
-                    // 判断是否上传文件
-                    if(this.fileCheck) {
-                        item.required = false
-                    }
-                });
-            }
-            return rules
-        }
+    rule() {
+      let rules = this.widget.rules || [];
+      if (rules && rules.length > 0) {
+        rules.forEach((item) => {
+          if (item.pattern) {
+            item.pattern = eval(item.pattern);
+          }
+          // 判断是否上传文件
+          if (this.fileCheck) {
+            item.required = false;
+          }
+        });
+      }
+      return rules;
     },
-    watch: {
-        // dataModel: {
-        //     deep: true,
-        //     handler(newValue) {
-        //         if (newValue !== undefined && newValue !== null) {
-        //         }
-        //     }
-        // },
-    }
-}
+  },
+  watch: {
+    // dataModel: {
+    //     deep: true,
+    //     handler(newValue) {
+    //         if (newValue !== undefined && newValue !== null) {
+    //         }
+    //     }
+    // },
+  },
+};
 </script>
 
-<style lang='less' scoped>
-@import url('./controlCommon.less');
+<style lang="less" scoped>
+@import url("./controlCommon.less");
 /deep/.van-uploader__wrapper--disabled {
-    opacity: 0.9;
+  opacity: 0.9;
 }
-</style>
+</style>

+ 142 - 75
src/views/message/control/input.vue

@@ -1,86 +1,153 @@
 <template>
-    <div class="oInput controller" :class="[preview ? '' : 'o-unit']" v-if="widget.type == 'input'">
-        <van-field
-            :name="widget.model"
-            v-model="dataModel"
-            :label="widget.name || '文本框'"
-            :type="inputType"
-            :required="fileCheck ? false : options.required || false"
-            :disabled="options.disabled || false"
-            clearable
-            :placeholder="options.placeholder || '请输入'"
-            autocomplete="off"
-            :rules="rule"
-            v-if="!preview"
-        />
-        <van-cell class="preview" :title="widget.name || '文本框'" :value="dataModel" v-else></van-cell>
-    </div>
+  <div
+    class="oInput controller"
+    :class="[preview ? '' : 'o-unit']"
+    v-if="widget.type == 'input'"
+  >
+    <van-field
+      :name="widget.model"
+      v-model="dataModel"
+      :label="widget.name || '文本框'"
+      :type="inputType"
+      :required="fileCheck ? false : options.required || false"
+      :disabled="options.disabled || false"
+      clearable
+      :placeholder="options.placeholder || '请输入'"
+      autocomplete="off"
+      :formatter="onFormatter"
+      :rules="rule"
+      v-if="!preview"
+    />
+    <van-cell
+      class="preview"
+      :title="widget.name || '文本框'"
+      :value="dataModel"
+      v-else
+    ></van-cell>
+  </div>
 </template>
 <script>
-
 export default {
-    name: 'oInput',
-    props: ['widget', 'preview', 'value', 'fileCheck'],
-    data() {
-        return {
-            dataModel: this.widget.options?.defaultValue || null,
-            inputType: null
-        }
-    },
-    mounted() {
-        // 初始化参数
-        let type = null
-        if(this.options.dataType === 'integer') {
-            type = 'digit'
-        } else if(this.options.dataType === 'float' || this.options.dataType.number) {
-            type = 'number'
-        }
-        this.inputType = type
+  name: "oInput",
+  props: ["widget", "preview", "value", "fileCheck"],
+  data() {
+    return {
+      dataModel: this.widget.options?.defaultValue || null,
+      inputType: null,
+    };
+  },
+  mounted() {
+    // 初始化参数
+    // let type = null;
+    // if (this.options.dataType === "integer") {
+    //   type = "text";
+    // } else if (
+    //   this.options.dataType === "float" ||
+    //   this.options.dataType.number
+    // ) {
+    //   type = "text";
+    // }
+    this.inputType = "text";
 
-        if(this.value) {
-            const widget = this.widget
-            const model = widget.originModel || widget.model
-            for(let v in this.value) {
-                if(v == model) {
-                    this.dataModel = this.value[v]
-                }
-            }
+    if (this.value) {
+      const widget = this.widget;
+      const model = widget.originModel || widget.model;
+      for (let v in this.value) {
+        if (v == model) {
+          this.dataModel = this.value[v];
         }
+      }
+    }
+  },
+  methods: {
+    verifyNumberIntegerAndFloat(val) {
+      // val = this.ruleForm.test;
+      const t = val.charAt(0);
+      // 匹配空格
+      // console.log(val)
+      let v = val.replace(/(^\s*)|(\s*$)/g, "");
+      // 只能是数字和小数点,不能是其他输入
+      v = v.replace(/[^\d.]/g, "");
+      // 以0开始只能输入一个
+      v = v.replace(/^0{2}$/g, "0");
+      // 保证第一位只能是数字,不能是点
+      v = v.replace(/^\./g, "");
+      // 小数只能出现1位
+      v = v
+        .replace(".", "$#$")
+        .replace(/\./g, "")
+        .replace("$#$", ".");
+      // 小数点后面保留2位
+      v = v.replace(/^(\-)*(\d+)\.(\d\d).*$/, "$1$2.$3");
+      if (t == "-") {
+        v = "-" + v;
+      }
+      // 返回结果
+      return v;
     },
-    methods: {
+    onVerifiyNumberInteger(val) {
+      const t = val.charAt(0);
+      // 匹配空格
+      let v = val.replace(/(^\s*)|(\s*$)/g, "");
+      // 去掉 '.' , 防止贴贴的时候出现问题 如 0.1.12.12
+      v = v.replace(/[\.]*/g, "");
+      // 去掉以 0 开始后面的数, 防止贴贴的时候出现问题 如 00121323
+      v = v.replace(/(^0[\d]*)$/g, "0");
+      // 首位是0,只能出现一次
+      v = v.replace(/^0\d$/g, "0");
+      // 只匹配数字
+      v = v.replace(/[^\d]/g, "");
+      if (t == "-") {
+        v = "-" + v;
+      }
+      // 返回结果
+      return v;
     },
-    computed: {
-        options() {
-            return this.widget.options || {}
-        },
-        rule() {
-            let rules = this.widget.rules || []
-            if(rules && rules.length > 0) {
-                rules.forEach(item => {
-                    if(item.pattern) {
-                        item.pattern = eval(item.pattern)
-                    }
-                    // 判断是否上传文件
-                    if(this.fileCheck) {
-                        item.required = false
-                    }
-                });
-            }
-            return rules
-        }
+    onFormatter(val) {
+      if (this.options.dataType === "integer") {
+        return this.onVerifiyNumberInteger(val);
+      } else if (
+        this.options.dataType === "float" ||
+        this.options.dataType.number
+      ) {
+        return this.verifyNumberIntegerAndFloat(val);
+      } else {
+        return val;
+      }
     },
-    watch: {
-        // dataModel: {
-        //     deep: true,
-        //     handler(newValue) {
-        //         if (newValue !== undefined && newValue !== null) {
-        //         }
-        //     }
-        // },
-    }
-}
+  },
+  computed: {
+    options() {
+      return this.widget.options || {};
+    },
+    rule() {
+      let rules = this.widget.rules || [];
+      if (rules && rules.length > 0) {
+        rules.forEach((item) => {
+          if (item.pattern) {
+            item.pattern = eval(item.pattern);
+          }
+          // 判断是否上传文件
+          if (this.fileCheck) {
+            item.required = false;
+          }
+        });
+      }
+      return rules;
+    },
+  },
+  watch: {
+    // dataModel: {
+    //     deep: true,
+    //     handler(newValue) {
+    //         if (newValue !== undefined && newValue !== null) {
+    //         }
+    //     }
+    // },
+  },
+};
 </script>
 
-<style lang='less' scoped>
-@import url('./controlCommon.less');
-</style>
+<style lang="less" scoped>
+@import url("./controlCommon.less");
+</style>

+ 153 - 140
src/views/message/control/organ.vue

@@ -1,157 +1,170 @@
 <template>
-    <div class="oOrgan controller" :class="[preview ? '' : 'o-unit']" v-if="widget.type == 'organ'">
-        <van-field
-            :name="widget.model"
-            v-model="dataModel"
-            :label="widget.name || '文本框'"
-            :required="fileCheck ? false : options.required || false"
-            :disabled="options.disabled || false"
-            clearable
-            readonly
-            :placeholder="options.placeholder || '请输入'"
-            :rules="rule"
-            clear-trigger="always"
-            @click="onClick"
-            v-if="!preview"
-        >
-            <template #right-icon>
-                <i class="van-icon van-icon-arrow van-cell__right-icon"></i>
-            </template>
-        </van-field>
+  <div
+    class="oOrgan controller"
+    :class="[preview ? '' : 'o-unit']"
+    v-if="widget.type == 'organ'"
+  >
+    <van-field
+      :name="widget.model"
+      v-model="dataModel"
+      :label="widget.name || '文本框'"
+      :required="fileCheck ? false : options.required || false"
+      :disabled="options.disabled || false"
+      clearable
+      readonly
+      :placeholder="options.placeholder || '请输入'"
+      :rules="rule"
+      clear-trigger="always"
+      @click="onClick"
+      v-if="!preview"
+    >
+      <template #right-icon>
+        <i class="van-icon van-icon-arrow van-cell__right-icon"></i>
+      </template>
+    </van-field>
 
-        <van-cell class="preview" :border="false" :title="widget.name || '文本框'" :value="dataModel" v-else></van-cell>
+    <van-cell
+      class="preview"
+      :border="false"
+      :title="widget.name || '文本框'"
+      :value="dataModel"
+      v-else
+    ></van-cell>
 
-        <!-- 处理显示问题 -->
-        <div class="valueShow" v-if="showDataModel && !preview">{{ showDataModel }}</div>
-        <div class="valueShow valuePreview" v-if="showDataModel && preview">
-            {{ showDataModel }}
-            <input type="hidden" :name="widget.model" :value="dataModel">
-        </div>
-
-        <van-popup v-model="showSelect" position="bottom">
-            <van-picker
-                show-toolbar
-                :columns="columns"
-                @confirm="onConfirm"
-                visible-item-count="4"
-                @cancel="onCancel"
-            />
-        </van-popup>
+    <!-- 处理显示问题 -->
+    <div class="valueShow" v-if="showDataModel && !preview">
+      {{ showDataModel }}
+    </div>
+    <div class="valueShow valuePreview" v-if="showDataModel && preview">
+      {{ showDataModel }}
+      <input type="hidden" :name="widget.model" :value="dataModel" />
     </div>
+
+    <van-popup v-model="showSelect" position="bottom">
+      <van-picker
+        show-toolbar
+        :columns="columns"
+        @confirm="onConfirm"
+        visible-item-count="4"
+        @cancel="onCancel"
+      />
+    </van-popup>
+  </div>
 </template>
 <script>
 // import { queryEmployeeOrgan } from '@/views/payAppeal/api'
 export default {
-    name: 'oOrgan',
-    props: ['widget', 'preview', 'value', 'fileCheck'],
-    data() {
-        return {
-            dataModel: this.widget.options?.defaultValue || null,
-            showDataModel: null,
-            showSelect: false,
-            columns: []
+  name: "oOrgan",
+  props: ["widget", "preview", "value", "fileCheck"],
+  data() {
+    return {
+      dataModel: this.widget.options?.defaultValue || null,
+      showDataModel: null,
+      showSelect: false,
+      columns: [],
+    };
+  },
+  async mounted() {
+    // 初始化参数
+    await this.$store.dispatch("setAllBranch");
+    await this.getList();
+    if (this.value) {
+      const widget = this.widget;
+      const model = widget.originModel || widget.model;
+      for (let v in this.value) {
+        if (v == model) {
+          this.dataModel = this.value[v];
         }
-    },
-    async mounted() {
-        // 初始化参数
-        await this.$store.dispatch('setAllBranch')
-        await this.getList()
-        if(this.value) {
-            const widget = this.widget
-            const model = widget.originModel || widget.model
-            for(let v in this.value) {
-                if(v == model) {
-                    this.dataModel = this.value[v]
-                }
-            }
-            // 反显分部
-            // console.log(this.dataModel)
-            // console.log(this.columns)
-            this.columns.forEach(item => {
-                if(this.dataModel == item.value) {
-                    this.showDataModel = item.text
-                }
-            })
+      }
+      // 反显分部
+      // console.log(this.dataModel)
+      // console.log(this.columns)
+      this.columns.forEach((item) => {
+        if (this.dataModel == item.value) {
+          this.showDataModel = item.text;
         }
+      });
+    }
+  },
+  methods: {
+    onClick() {
+      this.showSelect = true;
     },
-    methods: {
-        onClick() {
-            this.showSelect = true
-        },
-        onConfirm(val) {
-            this.dataModel = val.value
-            this.showDataModel = val.text
-            this.showSelect = false
-        },
-        onCancel() {
-            this.showSelect = false
-        },
-        async getList() {
-            // 获取所有分部
-            try {
-                this.columns = []
-                // let res = await queryEmployeeOrgan()
-                let res = this.selects.allBranch
-                // console.log(res)
-                let tempRes = res || []
-                tempRes.forEach(item => {
-                    this.columns.push({
-                        text: item.name,
-                        value: item.id
-                    })
-                })
-            } catch {
-                //
-            }
-        }
+    onConfirm(val) {
+      this.dataModel = val.value;
+      this.showDataModel = val.text;
+      this.showSelect = false;
     },
-    computed: {
-        options() {
-            return this.widget.options || {}
-        },
-        rule() {
-            let rules = this.widget.rules || []
-            if(rules && rules.length > 0) {
-                rules.forEach(item => {
-                    if(item.pattern) {
-                        item.pattern = eval(item.pattern)
-                    }
-                    // 判断是否上传文件
-                    if(this.fileCheck) {
-                        item.required = false
-                    }
-                });
-            }
-            return rules
-        }
+    onCancel() {
+      this.showSelect = false;
     },
-    watch: {
-        // dataModel: {
-        //     deep: true,
-        //     handler(newValue) {
-        //         if (newValue !== undefined && newValue !== null) {
-        //         }
-        //     }
-        // },
-    }
-}
+    async getList() {
+      // 获取所有分部
+      try {
+        this.columns = [];
+        // let res = await queryEmployeeOrgan()
+        let res = this.selects.allBranch;
+        console.log(res, "res");
+        // console.log(res)
+        let tempRes = res || [];
+        tempRes.forEach((item) => {
+          this.columns.push({
+            text: item.value,
+            value: item.key,
+          });
+        });
+      } catch {
+        //
+      }
+    },
+  },
+  computed: {
+    options() {
+      return this.widget.options || {};
+    },
+    rule() {
+      let rules = this.widget.rules || [];
+      if (rules && rules.length > 0) {
+        rules.forEach((item) => {
+          if (item.pattern) {
+            item.pattern = eval(item.pattern);
+          }
+          // 判断是否上传文件
+          if (this.fileCheck) {
+            item.required = false;
+          }
+        });
+      }
+      return rules;
+    },
+  },
+  watch: {
+    // dataModel: {
+    //     deep: true,
+    //     handler(newValue) {
+    //         if (newValue !== undefined && newValue !== null) {
+    //         }
+    //     }
+    // },
+  },
+};
 </script>
 
-<style lang='less' scoped>
-@import url('./controlCommon.less');
+<style lang="less" scoped>
+@import url("./controlCommon.less");
 .oOrgan {
-    position: relative;
-    .valueShow {
-        position: absolute;
-        bottom: 12px;
-        left: 16px;
-        line-height: 24px;
-        padding: .03rem 0;
-        background: #fff;
-        min-width: 120px;
-    }
-    .valuePreview {
-        bottom: 2px;
-    }
+  position: relative;
+  .valueShow {
+    position: absolute;
+    bottom: 12px;
+    left: 16px;
+    line-height: 24px;
+    padding: 0.03rem 0;
+    background: #fff;
+    min-width: 120px;
+  }
+  .valuePreview {
+    bottom: 2px;
+  }
 }
-</style>
+</style>

+ 51 - 51
src/views/message/control/text.vue

@@ -1,52 +1,52 @@
-<template>
-    <div class="oText" v-if="widget.type == 'text'">
-        <p class="text-content" :class="[preview ? 'textMarginTop' : null]">{{ dataModel }}</p>
-    </div>
-</template>
-<script>
-
-export default {
-    name: 'oText',
-    props: ['widget', 'preview'],
-    data() {
-        return {
-            dataModel: this.widget.options?.defaultValue || null,
-        }
-    },
-    mounted() {
-        // 初始化参数
-    },
-    methods: {
-    },
-    computed: {
-        options() {
-            return this.widget.options || {}
-        },
-    },
-    watch: {
-        // dataModel: {
-        //     deep: true,
-        //     handler(newValue) {
-        //         if (newValue !== undefined && newValue !== null) {
-        //         }
-        //     }
-        // },
-    }
-}
-</script>
-
-<style lang='less' scoped>
-.oText {
-    // margin-bottom: 5px;
-    padding: 12px 0 5px;
-    .text-content {
-        font-size: .12rem;
-        color: #777777;
-        padding: 0 .16rem;
-        &.textMarginTop {
-            margin-top: 5px;
-            // padding: 0;
-        }
-    }
-}
+<template>
+    <div class="oText" v-if="widget.type == 'text'">
+        <p class="text-content" :class="[preview ? 'textMarginTop' : null]">{{ dataModel }}</p>
+    </div>
+</template>
+<script>
+
+export default {
+    name: 'oText',
+    props: ['widget', 'preview'],
+    data() {
+        return {
+            dataModel: this.widget.options?.defaultValue || null,
+        }
+    },
+    mounted() {
+        // 初始化参数
+    },
+    methods: {
+    },
+    computed: {
+        options() {
+            return this.widget.options || {}
+        },
+    },
+    watch: {
+        // dataModel: {
+        //     deep: true,
+        //     handler(newValue) {
+        //         if (newValue !== undefined && newValue !== null) {
+        //         }
+        //     }
+        // },
+    }
+}
+</script>
+
+<style lang='less' scoped>
+.oText {
+    // margin-bottom: 5px;
+    padding: 12px 0 5px;
+    .text-content {
+        font-size: .12rem;
+        color: #777777;
+        padding: 0 .16rem;
+        &.textMarginTop {
+            margin-top: 5px;
+            // padding: 0;
+        }
+    }
+}
 </style>

+ 77 - 69
src/views/message/control/textarea.vue

@@ -1,79 +1,87 @@
 <template>
-    <div class="oTextarea controller" :class="[preview ? '' : 'o-unit']" v-if="widget.type == 'textarea'">
-        <van-field
-            :name="widget.model"
-            v-model="dataModel"
-            :label="widget.name || '文本框'"
-            :required="fileCheck ? false : options.required || false"
-            :disabled="options.disabled || false"
-            :show-error="false"
-            :scroll-to-error="true"
-            :placeholder="options.placeholder || '请输入'"
-            type="textarea"
-            clearable
-            :autosize=" { maxHeight: 120, minHeight: 60 }"
-            :rules="rule"
-            v-if="!preview"
-        />
-        <van-cell class="preview" :title="widget.name || '文本框'" :value="dataModel" v-else></van-cell>
-    </div>
+  <div
+    class="oTextarea controller"
+    :class="[preview ? '' : 'o-unit']"
+    v-if="widget.type == 'textarea'"
+  >
+    <van-field
+      :name="widget.model"
+      v-model="dataModel"
+      :label="widget.name || '文本框'"
+      :required="fileCheck ? false : options.required || false"
+      :disabled="options.disabled || false"
+      :show-error="false"
+      :scroll-to-error="true"
+      :placeholder="options.placeholder || '请输入'"
+      type="textarea"
+      clearable
+      :autosize="{ maxHeight: 120, minHeight: 60 }"
+      :rules="rule"
+      v-if="!preview"
+    />
+    <van-cell class="preview" :title="widget.name || '文本框'" v-else>
+      <p v-html="dataModelFormatBr(dataModel)"></p>
+    </van-cell>
+  </div>
 </template>
 <script>
-
 export default {
-    name: 'oTextarea',
-    props: ['widget', 'preview', 'value', 'fileCheck'],
-    data() {
-        return {
-            dataModel: this.widget.options?.defaultValue || null,
-        }
-    },
-    mounted() {
-        // 初始化参数
-        if(this.value) {
-            const widget = this.widget
-            const model = widget.originModel || widget.model
-            for(let v in this.value) {
-                if(v == model) {
-                    this.dataModel = this.value[v]
-                }
-            }
+  name: "oTextarea",
+  props: ["widget", "preview", "value", "fileCheck"],
+  data() {
+    return {
+      dataModel: this.widget.options?.defaultValue || null,
+    };
+  },
+  mounted() {
+    // 初始化参数
+    if (this.value) {
+      const widget = this.widget;
+      const model = widget.originModel || widget.model;
+      for (let v in this.value) {
+        if (v == model) {
+          this.dataModel = this.value[v];
         }
+      }
+    }
+  },
+  methods: {
+    dataModelFormatBr(str) {
+      return str ? str.replace(/\n/g, "<br />") : str;
     },
-    methods: {
+  },
+  computed: {
+    options() {
+      return this.widget.options || {};
     },
-    computed: {
-        options() {
-            return this.widget.options || {}
-        },
-        rule() {
-            let rules = this.widget.rules || []
-            if(rules && rules.length > 0) {
-                rules.forEach(item => {
-                    if(item.pattern) {
-                        item.pattern = eval(item.pattern)
-                    }
-                    // 判断是否上传文件
-                    if(this.fileCheck) {
-                        item.required = false
-                    }
-                });
-            }
-            return rules
-        }
+    rule() {
+      let rules = this.widget.rules || [];
+      if (rules && rules.length > 0) {
+        rules.forEach((item) => {
+          if (item.pattern) {
+            item.pattern = eval(item.pattern);
+          }
+          // 判断是否上传文件
+          if (this.fileCheck) {
+            item.required = false;
+          }
+        });
+      }
+      return rules;
     },
-    watch: {
-        // dataModel: {
-        //     deep: true,
-        //     handler(newValue) {
-        //         if (newValue !== undefined && newValue !== null) {
-        //         }
-        //     }
-        // },
-    }
-}
+  },
+  watch: {
+    // dataModel: {
+    //     deep: true,
+    //     handler(newValue) {
+    //         if (newValue !== undefined && newValue !== null) {
+    //         }
+    //     }
+    // },
+  },
+};
 </script>
 
-<style lang='less' scoped>
-@import url('./controlCommon.less');
-</style>
+<style lang="less" scoped>
+@import url("./controlCommon.less");
+</style>

BIN=BIN
src/views/message/images/icon_commit.png


BIN=BIN
src/views/message/images/icon_upload_file.png


BIN=BIN
src/views/message/images/icon_upload_img.png


+ 203 - 0
src/views/message/modal/filePreview.vue

@@ -0,0 +1,203 @@
+<template>
+  <div>
+    <van-field class="preview">
+      <template #input>
+        <div
+          class="preview_file"
+          v-for="(item, index) in dataModel"
+          :key="index"
+        >
+          <div class="preview_item">
+            <i
+              class="van-icon van-icon-description van-uploader__file-icon"
+            ></i>
+            <span
+              style="white-space: nowrap;overflow: hidden;text-overflow: ellipsis;width: 1.8rem;"
+              >{{ item.name || item.url }}</span
+            >
+          </div>
+          <div class="preview_btn">
+            <van-button @click="downLoadFile2(item.url)" type="info" size="mini"
+              >下载</van-button
+            >
+            <van-button
+              :disabled="!checkFileSuffix(item.url)"
+              v-if="checkFileSuffix(item.url)"
+              @click="downLoadFile(item.url)"
+              type="info"
+              size="mini"
+              >预览</van-button
+            >
+          </div>
+        </div>
+      </template>
+    </van-field>
+
+    <van-popup position="bottom" v-model="filePreview" style="height: 100%;">
+      <van-sticky>
+        <m-header :backUrl="backUrl" :isFixed="false" name="预览" />
+      </van-sticky>
+      <div
+        id="previewIframe"
+        style="height: calc(100vh - 0.44rem);"
+        v-if="filePreview && (fileType == 'xls' || fileType == 'pdf')"
+      ></div>
+      <div
+        style="height: calc(100vh - 0.44rem);"
+        v-if="filePreview && fileType == 'doc'"
+      ></div>
+    </van-popup>
+  </div>
+</template>
+
+<script>
+import MHeader from "@/components/MHeader";
+import { browser } from "@/common/util";
+import { postMessage } from "@/helpers/native-message";
+export default {
+  props: ["dataModel"],
+  components: { MHeader },
+  data() {
+    return {
+      filePreview: false,
+      fileType: "xls",
+      previewUrl: "",
+      backUrl: {
+        status: true,
+        callBack: () => {
+          this.filePreview = false;
+        },
+      },
+    };
+  },
+  mounted() {
+    console.log(this.dataModel);
+  },
+  methods: {
+    checkFileSuffix(url) {
+      let urlArr = url.split(".");
+      let suffix = urlArr[urlArr.length - 1];
+      //  || suffix == 'doc' || suffix == 'docx'
+      if (suffix == "xlsx" || suffix == "xls" || suffix == "pdf") {
+        return true;
+      } else {
+        return false;
+      }
+    },
+    getFileSuffix(url) {
+      let urlArr = url.split(".");
+      let suffix = urlArr[urlArr.length - 1];
+      if (suffix == "xlsx" || suffix == "xls") {
+        return "xls";
+      } else if (suffix == "doc" || suffix == "docx") {
+        return "doc";
+      } else if (suffix == "pdf") {
+        return "pdf";
+      } else {
+        return "";
+      }
+    },
+    downLoadFile2(file) {
+      this.$toast.loading({
+        duration: 0, // 持续展示 toast
+        forbidClick: true,
+        message: "下载中...",
+      });
+      if (browser().isApp) {
+        postMessage(
+          { api: "downloadFile", content: { downloadUrl: file } },
+          () => {
+            this.$toast.clear();
+          }
+        );
+      } else {
+        this.$toast.clear();
+        window.location.href = file;
+      }
+    },
+    downLoadFile(file) {
+      // this.previewUrl = 'https://view.officeapps.live.com/op/view.aspx?src=' + file
+      this.filePreview = true;
+      this.fileType = this.getFileSuffix(file);
+
+      if (this.fileType == "xls" || this.fileType == "pdf") {
+        this.$toast.loading({
+          duration: 0, // 持续展示 toast
+          forbidClick: true,
+          message: "加载中...",
+        });
+        let _this = this;
+        this.$nextTick(() => {
+          let iframe = document.createElement("iframe");
+          iframe.id = "preview_iframe";
+          iframe.style.width = "100%";
+          iframe.style.height = "100%";
+          iframe.style.border = "none";
+          if (this.fileType == "xls") {
+            if (browser().android) {
+              iframe.src =
+                "https://api.idocv.com/view/url?url=" +
+                encodeURIComponent(file + "?times=" + new Date().getTime());
+            } else {
+              iframe.src =
+                "https://view.officeapps.live.com/op/view.aspx?src=" + file;
+            }
+          } else {
+            iframe.src =
+              window.location.origin +
+              "/pdf/web/viewer.html?file=" +
+              encodeURIComponent(file);
+          }
+          if (iframe.attachEvent) {
+            iframe.attachEvent("onload", function() {
+              _this.$toast.clear();
+            });
+          } else {
+            iframe.onload = function() {
+              _this.$toast.clear();
+
+              // setTimeout(() => {
+              //     let dom =  document.querySelector('#preview_iframe').contentWindow.document
+              //     let scripts = dom.querySelectorAll('script[src]')
+              //     if(scripts)
+              // }, 2000);
+            };
+          }
+          document.querySelector("#previewIframe").appendChild(iframe);
+        });
+      } else if (this.fileType == "doc") {
+        //     // this.previewUrl = 'https://view.officeapps.live.com/op/view.aspx?src=' + file
+      }
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.preview {
+  padding: 0;
+  /deep/.van-field__control {
+    display: flex;
+    flex-direction: column;
+  }
+}
+.preview_file {
+  width: 100%;
+  font-size: 14px;
+  display: flex;
+  justify-content: space-between;
+  background: #f7f7f7;
+  padding: 0.08rem;
+  margin-bottom: 0.08rem;
+  box-sizing: border-box;
+  .preview_item {
+    display: flex;
+    align-items: center;
+    flex-basis: 70%;
+  }
+  .preview_btn {
+    text-align: right;
+    flex-basis: 30%;
+  }
+}
+</style>

+ 251 - 213
src/views/message/modal/transferModal.vue

@@ -1,86 +1,111 @@
 <template>
-    <van-form validate-first @submit="onSubmit" :show-error="false" class="popup-transfer controller">
-        <van-field
-            :label="'节点'"
-            clickable
-            :placeholder="'请选择节点'"
-            clear-trigger="always"
-            v-model="node_txt"
-            readonly
-            name="node_id"
-            required
-            @click="onSelect('node')"
-            :rules="[{ required: true, message: '请选择节点', trigger: 'onSubmit' }]"
-        >
-            <template #right-icon>
-                <i class="van-icon van-icon-arrow van-cell__right-icon"></i>
-            </template>
-        </van-field>
-        <van-field
-            :label="'用户'"
-            clickable
-            readonly
-            :placeholder="'请选择用户'"
-            clear-trigger="always"
-            v-model="user_txt"
-            name="user_id"
-            required
-            @click="showSelectUser = true"
-            :rules="[{ required: true, message: '请选择用户', trigger: 'onSubmit' }]"
-        >
-            <template #right-icon>
-                <i class="van-icon van-icon-arrow van-cell__right-icon"></i>
-            </template>
-        </van-field>
-        <van-field
-            label="备注"
-            name='remarks'
-            v-model="ruleForm.remarks"
-            type="textarea"
-            clearable
-            row="5"
-            :autosize=" { maxHeight: 120, minHeight: 80 }"
-            :placeholder="'请输入备注'"
-        />
-        <van-button type="info" round native-type="submit">确认</van-button>
+  <van-form
+    validate-first
+    @submit="onSubmit"
+    :show-error="false"
+    class="popup-transfer controller"
+  >
+    <van-field
+      :label="'节点'"
+      clickable
+      :placeholder="'请选择节点'"
+      clear-trigger="always"
+      v-model="node_txt"
+      readonly
+      name="node_id"
+      required
+      @click="onSelect('node')"
+      :rules="[{ required: true, message: '请选择节点', trigger: 'onSubmit' }]"
+    >
+      <template #right-icon>
+        <i class="van-icon van-icon-arrow van-cell__right-icon"></i>
+      </template>
+    </van-field>
+    <van-field
+      :label="'用户'"
+      clickable
+      readonly
+      :placeholder="'请选择用户'"
+      clear-trigger="always"
+      v-model="user_txt"
+      name="user_id"
+      required
+      @click="showSelectUser = true"
+      :rules="[{ required: true, message: '请选择用户', trigger: 'onSubmit' }]"
+    >
+      <template #right-icon>
+        <i class="van-icon van-icon-arrow van-cell__right-icon"></i>
+      </template>
+    </van-field>
+    <van-field
+      label="备注"
+      name="remarks"
+      v-model="ruleForm.remarks"
+      type="textarea"
+      clearable
+      row="5"
+      :autosize="{ maxHeight: 120, minHeight: 80 }"
+      :placeholder="'请输入备注'"
+    />
 
-        <van-popup v-model="showSelect" position="bottom">
-            <van-picker
-                show-toolbar
-                :columns="popupList"
-                @confirm="onConfirm"
-                :default-index="defaultIndex"
-                visible-item-count="4"
-                @cancel="showSelect = false"
-            />
-        </van-popup>
+    <div style="padding: 10px 16px">
+      <Upload :fileUrl="fileUrl" />
+    </div>
+    <van-button type="info" round native-type="submit">确认</van-button>
 
-        <van-popup v-model="showSelectUser" position="bottom" style="height: 60%">
-            <search class="transferSearch" @onSearch="onSearch" placeholder="请输入用户名" />
-            <div class="userList">
-                <template v-for="(item, index) in columnList">
-                    <div class="userItem" v-show="!item.hidden" :key="index" @click="onTeacherSelect(item)">
-                        <div class="userItem-title">
-                            <img v-if="item.avatar" class="logo" :src="item.avatar" fit="cover" />
-                            <img
-                                v-else
-                                class="logo"
-                                src="@/assets/images/icon_teacher.png"
-                                alt=""
-                            />
-                        </div>
-                        <div class="userItem-content">
-                            <div class="userItem-content-name">
-                                <span>{{item.text}}</span>
-                            </div>
-                            <div class="userItem-content-desc">
-                                <span>{{item.phone}}</span>
-                            </div>
-                        </div>
-                    </div>
-                </template>
+    <van-popup v-model="showSelect" position="bottom">
+      <van-picker
+        show-toolbar
+        :columns="popupList"
+        @confirm="onConfirm"
+        :default-index="defaultIndex"
+        visible-item-count="4"
+        @cancel="showSelect = false"
+      />
+    </van-popup>
+
+    <van-popup v-model="showSelectUser" position="bottom" style="height: 60%">
+      <search
+        class="transferSearch"
+        @onSearch="onSearch"
+        @onInput="onSearch"
+        placeholder="请输入用户名"
+      />
+      <div class="userList">
+        <template v-for="(item, index) in columnList">
+          <div
+            class="userItem"
+            v-show="!item.hidden"
+            :key="index"
+            @click="onTeacherSelect(item)"
+          >
+            <div class="userItem-title">
+              <img
+                v-if="item.avatar"
+                class="logo"
+                :src="item.avatar"
+                fit="cover"
+              />
+              <img
+                v-else
+                class="logo"
+                src="@/assets/images/icon_teacher.png"
+                alt=""
+              />
+            </div>
+            <div class="userItem-content">
+              <div class="userItem-content-name">
+                <span>{{ item.text }}</span>
+              </div>
+              <div class="userItem-content-desc">
+                <span>{{ item.phone }}</span>
+              </div>
             </div>
-            <!-- <van-picker
+          </div>
+        </template>
+        <m-empty v-if="showLength <= 0" />
+      </div>
+      <!-- <van-picker
                 show-toolbar
                 :columns="popupList"
                 @confirm="onConfirm"
@@ -88,153 +113,166 @@
                 visible-item-count="4"
                 @cancel="showSelect = false"
             /> -->
-        </van-popup>
-    </van-form>
+    </van-popup>
+  </van-form>
 </template>
 <script>
-import search from '@/components/Search.vue'
-import { inversionWorkOrder } from '../api'
+import search from "@/components/Search.vue";
+import MEmpty from "@/components/MEmpty";
+import { inversionWorkOrder } from "../api";
+import Upload from "./upload.vue";
 export default {
-    name: 'transfer',
-    props: ['popupForm', 'columns', 'nodeList'],
-    components: { search },
-    data() {
-        return {
-            node_txt: null,
-            nodeIndex: 0,
-            user_txt: null,
-            userIndex: 0,
-            ruleForm: {
-                work_order_id: '',
-                node_id: '',
-                user_id: '',
-                remarks: ''
-            },
-            showSelect: false,
-            showSelectUser: false,
-            popupList: [],
-            popupType: null,
-            defaultIndex: 0,
-            columnList: []
+  name: "transfer",
+  props: ["popupForm", "columns", "nodeList"],
+  components: { search, Upload, MEmpty },
+  data() {
+    return {
+      node_txt: null,
+      nodeIndex: 0,
+      user_txt: null,
+      userIndex: 0,
+      ruleForm: {
+        work_order_id: "",
+        node_id: "",
+        user_id: "",
+        remarks: "",
+      },
+      fileUrl: [],
+      showSelect: false,
+      showSelectUser: false,
+      popupList: [],
+      popupType: null,
+      defaultIndex: 0,
+      columnList: [],
+      showLength: 0,
+    };
+  },
+  async mounted() {
+    this.columnList = this.columns || [];
+    this.showLength = this.columnList.length;
+    this.ruleForm = this.popupForm;
+    if (this.ruleForm.node_id) {
+      this.nodeList.forEach((item) => {
+        if (item.id == this.ruleForm.node_id) {
+          this.node_txt = item.text;
         }
-    },
-    async mounted() {
-        this.columnList = this.columns
-        this.ruleForm = this.popupForm
-        if(this.ruleForm.node_id) {
-            this.nodeList.forEach(item => {
-                if(item.id == this.ruleForm.node_id) {
-                    this.node_txt = item.text
-                }
-            })
+      });
+    }
+  },
+  methods: {
+    onSearch(val) {
+      let showLength = 0;
+      this.columnList.forEach((item) => {
+        if (val) {
+          if (item.text.indexOf(val) != -1) {
+            item.hidden = false;
+          } else {
+            item.hidden = true;
+          }
+        } else {
+          item.hidden = false;
         }
-    },
-    methods: {
-        onSearch(val) {
-            this.columnList.forEach(item => {
-                if(val) {
-                    if(item.text.indexOf(val) != -1) {
-                        item.hidden = false
-                    } else {
-                        item.hidden = true
-                    }
-                } else {
-                    item.hidden = false
-                }
-            })
-            this.$forceUpdate()
-        },
-        async onSubmit() {
-            try {
-                await inversionWorkOrder({ ...this.ruleForm })
-                this.$toast('转交成功')
-                this.$router.replace({
-                    path: '/myApproval',
-                    query: {
-                        classify: this.$route.query.classify || 2
-                    }
-                })
-            } catch {
-                //
-            }
-        },
-        onTeacherSelect(item) {
-            this.ruleForm.user_id = item.id
-            this.user_txt = item.text
-            this.showSelectUser = false
-        },
-        onConfirm(value, index) {
-            if(this.popupType == 'users') {
-                this.userIndex = index
-                this.ruleForm.user_id = value.id
-                this.user_txt = value.text
-            } else if(this.popupType == 'node') {
-                this.nodeIndex = index
-                this.ruleForm.node_id = value.id
-                this.node_txt = value.text
-            }
-            this.showSelect = false
-        },
-        onSelect(type) {
-            this.popupType = type
-            if(type == 'users') {
-                this.popupList = this.columns
-                this.defaultIndex = this.userIndex
-            } else if(type == 'node') {
-                this.popupList = this.nodeList
-                this.defaultIndex = this.nodeIndex
-            }
-            this.showSelect = true
+        if (!item.hidden) {
+          showLength++;
         }
-    }
-}
+      });
+      this.showLength = showLength;
+      this.$forceUpdate();
+    },
+    async onSubmit() {
+      try {
+        await inversionWorkOrder({
+          ...this.ruleForm,
+          fileUrl: JSON.stringify(this.fileUrl || []),
+        });
+        this.$toast("转交成功");
+        this.$router.replace({
+          path: "/myApproval",
+          query: {
+            classify: this.$route.query.classify || 2,
+          },
+        });
+      } catch {
+        //
+      }
+    },
+    onTeacherSelect(item) {
+      this.ruleForm.user_id = item.id;
+      this.user_txt = item.text;
+      this.showSelectUser = false;
+    },
+    onConfirm(value, index) {
+      if (this.popupType == "users") {
+        this.userIndex = index;
+        this.ruleForm.user_id = value.id;
+        this.user_txt = value.text;
+      } else if (this.popupType == "node") {
+        this.nodeIndex = index;
+        this.ruleForm.node_id = value.id;
+        this.node_txt = value.text;
+      }
+      this.showSelect = false;
+    },
+    onSelect(type) {
+      this.popupType = type;
+      if (type == "users") {
+        this.popupList = this.columns;
+        this.defaultIndex = this.userIndex;
+      } else if (type == "node") {
+        this.popupList = this.nodeList;
+        this.defaultIndex = this.nodeIndex;
+      }
+      this.showSelect = true;
+    },
+  },
+};
 </script>
 
 <style lang="less" scoped>
-@import url('../control/controlCommon.less');
+@import url("../control/controlCommon.less");
 .popup-transfer {
-    /deep/.van-cell {
-        font-size: .14rem;
-    }
-    /deep/.van-button {
-        width: 90%;
-        margin-top: .12rem;
-        margin-left: 5%;
-        font-size: .16rem;
-    }
+  /deep/.van-cell {
+    font-size: 0.14rem;
+  }
+  /deep/.van-button {
+    width: 90%;
+    margin-top: 0.12rem;
+    margin-left: 5%;
+    font-size: 0.16rem;
+  }
 
-    .transferSearch {
-        /deep/.van-field {
-            flex-direction: row;
-            padding: 5px 8px 5px 0;
-        }
-        /deep/.van-field__value {
-            padding: 0;
-        }
+  .transferSearch {
+    /deep/.van-field {
+      flex-direction: row;
+      padding: 5px 8px 5px 0;
+    }
+    /deep/.van-field__value {
+      padding: 0;
     }
+  }
 
-    .userList {
-        height: calc(100% - 70px);
-        overflow-y: auto;
-        overflow-x: hidden;
+  .userList {
+    height: calc(100% - 70px);
+    overflow-y: auto;
+    overflow-x: hidden;
 
-        .logo {
-            width: 0.42rem;
-            height: 0.42rem;
-            margin-right: 0.12rem;
-            border-radius: 100%;
-        }
-        .userItem {
-            padding: 0.08rem 0.15rem 0;
-            display: flex;
-            align-items: center;
-        }
-        .userItem-content-name {
-            font-size: .15rem;
-        }
-        .userItem-content-desc {
-            font-size: .12rem;
-        }
+    .logo {
+      width: 0.42rem;
+      height: 0.42rem;
+      margin-right: 0.12rem;
+      border-radius: 100%;
+    }
+    .userItem {
+      padding: 0.08rem 0.15rem 0;
+      display: flex;
+      align-items: center;
+    }
+    .userItem-content-name {
+      font-size: 0.15rem;
+    }
+    .userItem-content-desc {
+      font-size: 0.12rem;
     }
+  }
 }
-</style>
+</style>

+ 310 - 0
src/views/message/modal/upload.vue

@@ -0,0 +1,310 @@
+<template>
+  <div class="uploader">
+    <div class="preview-container">
+      <div class="preview-list">
+        <div
+          class="preview-item"
+          v-for="(item, index) in tempFileUrl"
+          :key="index"
+        >
+          <div class="preview-item-img" v-if="item.type == 'image'">
+            <van-image :src="item.url" fit="cover" />
+          </div>
+          <div class="preview-item-img" v-if="item.type == 'file'">
+            <i
+              class="van-icon van-icon-description van-uploader__file-icon"
+            ></i>
+            <span
+              style="
+                white-space: nowrap;
+                overflow: hidden;
+                text-overflow: ellipsis;
+                width: 64px;
+                font-size: 13px;
+                padding-top: 5px;
+              "
+              >{{ item.name }}</span
+            >
+          </div>
+          <div class="preview-item-close">
+            <van-icon name="cross" @click="onDelete(item)" />
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <div class="upload_section">
+      <van-uploader
+        :before-read="beforeRead"
+        :after-read="afterRead"
+        :disabled="false"
+      >
+        <div class="upload-file">
+          <img src="../images/icon_upload_img.png" />
+          上传图片
+        </div>
+      </van-uploader>
+
+      <van-uploader
+        style="margin-left: 4%"
+        :before-read="beforeReadFile"
+        :after-read="afterRead"
+        :disabled="false"
+        accept="image/*, *.xlsx, *.xls,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel, application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document, *.txt, *.pdf"
+      >
+        <div class="upload-file">
+          <img src="../images/icon_upload_file.png" />
+          上传附件
+        </div>
+      </van-uploader>
+    </div>
+  </div>
+</template>
+
+<script>
+// import setLoading from "@/common/loading";
+// import { uploadFile } from "../api";
+import { policy } from "@/views/massMessage/api";
+import axios from "axios";
+export default {
+  name: "upload",
+  props: ["fileUrl"],
+  data() {
+    return {
+      tempFileUrl: this.fileUrl || [],
+      type: "image",
+      ossUploadUrl: "https://ks3-cn-beijing.ksyuncs.com/daya",
+      dataObj: {
+        policy: "",
+        signature: "",
+        key: "",
+        KSSAccessKeyId: "",
+        acl: "public-read",
+        name: "",
+      },
+    };
+  },
+  watch: {
+    fileUrl(val) {
+      this.tempFileUrl = val;
+    },
+  },
+  methods: {
+    onDelete(item) {
+      const index = this.tempFileUrl.indexOf(item);
+      this.tempFileUrl.splice(index, 1);
+      this.$emit("fileUrl", this.tempFileUrl);
+    },
+    beforeRead(file) {
+      const isLt2M = file.size / 1024 / 1024 < 5;
+      if (!isLt2M) {
+        this.$toast("上传图片大小不能超过 5MB");
+        return false;
+      }
+      const fileList = this.tempFileUrl.map((item) => {
+        if (item.type == "image") {
+          return item;
+        }
+      });
+      if (fileList.length >= 5) {
+        this.$toast("最多上传5张图片");
+        return false;
+      }
+      this.type = "image";
+      return true;
+    },
+    beforeReadFile(file) {
+      const isLt2M = file.size / 1024 / 1024 < 20;
+      if (!isLt2M) {
+        this.$toast("上传文件大小不能超过 20MB");
+        return false;
+      }
+      const fileList = this.tempFileUrl.map((item) => {
+        if (item.type == "file") {
+          return item;
+        }
+      });
+      if (fileList.length >= 3) {
+        this.$toast("最多上传3个附件");
+        return false;
+      }
+      this.type = "file";
+      return true;
+    },
+    async afterRead(file) {
+      // 上传头像
+      // 上传头像
+      try {
+        file.status = "uploading";
+        file.message = "上传中...";
+        let tempName = file.file.name || "";
+        const fileName = tempName && tempName.replace(/ /gi, "_");
+        let key = new Date().getTime() + fileName;
+        let objTemp = {
+          filename: fileName,
+          bucketName: this.bucket_name,
+          postData: {
+            filename: fileName,
+            acl: "public-read",
+            key: key,
+            unknowValueField: [],
+          },
+        };
+
+        const res = await policy(objTemp);
+        const obj = {
+          policy: res.data.policy,
+          signature: res.data.signature,
+          key: key,
+          KSSAccessKeyId: res.data.kssAccessKeyId,
+          acl: "public-read",
+          name: fileName,
+        };
+
+        let formData = new FormData();
+        for (let key in obj) {
+          formData.append(key, obj[key]);
+        }
+        formData.append("file", file.file);
+        await axios({
+          method: "post",
+          url: this.ossUploadUrl,
+          data: formData,
+        });
+        const uploadUrl = this.ossUploadUrl + "/" + key;
+        file.status = "done";
+        this.tempFileUrl.push({
+          url: uploadUrl,
+          name: file.file.name,
+          type: this.type,
+          file: {
+            // 为了处理pc端显示文件名称
+            name: file.file.name,
+          },
+        });
+
+        this.$emit("update:fileUrl", this.tempFileUrl);
+      } catch (e) {
+        //
+        file.status = "failed";
+        file.message = "上传失败";
+        return false;
+      }
+      // try {
+      //   setLoading(true);
+      //   file.status = "uploading";
+      //   file.message = "上传中...";
+      //   let formData = new FormData();
+      //   formData.append("file", file.file);
+      //   let res = await uploadFile(formData);
+      //   let result = res.data;
+      //   if (result.code == 200) {
+      //     file.status = "done";
+      //     this.tempFileUrl.push({
+      //       url: result.data.url,
+      //       name: file.file.name,
+      //       type: this.type,
+      //       file: {
+      //         // 为了处理pc端显示文件名称
+      //         name: file.file.name,
+      //       },
+      //     });
+
+      //     this.$emit("update:fileUrl", this.tempFileUrl);
+      //   } else {
+      //     file.status = "failed";
+      //     file.message = "上传失败";
+      //     this.$toast(result.msg);
+      //     return false;
+      //   }
+      //   setLoading(false);
+      // } catch (err) {
+      //   setLoading(false);
+      //   return false;
+      // }
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.preview-container::-webkit-scrollbar {
+  display: none;
+}
+.preview-container {
+  width: 100%;
+  overflow: hidden;
+  overflow-y: hidden;
+  overflow-x: auto;
+}
+.preview-list {
+  display: flex;
+}
+.preview-item {
+  position: relative;
+  margin: 0 8px 8px 0;
+  border-radius: 4px;
+  overflow: hidden;
+}
+.preview-item,
+.preview-item-img {
+  background: #f7f8fa;
+  width: 64px;
+  height: 64px;
+  display: flex;
+  align-items: center;
+  flex-direction: column;
+  justify-content: center;
+  /deep/.van-image {
+    width: 100%;
+    height: 100%;
+  }
+}
+
+.preview-item-close {
+  position: absolute;
+  top: 0;
+  right: 0;
+  width: 14px;
+  height: 14px;
+  background-color: rgba(0, 0, 0, 0.7);
+  border-radius: 0 0 0 12px;
+
+  /deep/.van-icon {
+    position: absolute;
+    top: -2px;
+    right: -2px;
+    color: #fff;
+    font-size: 16px;
+    -webkit-transform: scale(0.5);
+    transform: scale(0.5);
+  }
+}
+
+.upload_section {
+  display: flex;
+  align-content: center;
+  /deep/.van-uploader {
+    width: 48%;
+  }
+  /deep/.van-uploader__wrapper,
+  /deep/.van-uploader__input-wrapper {
+    width: 100%;
+  }
+}
+.upload-file {
+  background: #f7f8f9;
+  border-radius: 9px;
+  padding: 0.12rem 0.14rem;
+  display: flex;
+  align-content: center;
+  justify-content: center;
+  font-size: 0.14rem;
+  font-weight: 500;
+  color: #01c1b5;
+  img {
+    height: 22px;
+    margin-right: 0.19rem;
+  }
+}
+</style>

+ 37 - 33
src/views/teacher/Business.vue

@@ -2,26 +2,30 @@
   <div class="business">
     <m-header />
 
-    <!-- <section class="module m-shadow">
-            <h2 class="title">审批</h2>
-            <div class="module-item">
-                <router-link :to="{ path: '/approval' }"
-                            class="module-link"><i class="icon icon_1"></i>需我审批</router-link>
-                <router-link :to="{ path: '/istarted' }" 
+    <section class="module m-shadow">
+      <h2 class="title">审批</h2>
+      <div class="module-item">
+        <router-link :to="{ path: '/approval' }" class="module-link"
+          ><i class="icon icon_1"></i>OA审批</router-link
+        >
+        <!-- <router-link :to="{ path: '/istarted' }" 
                             class="module-link"><i class="icon icon_2"></i>我发起的</router-link>
                 <router-link :to="{ path: '/ccme' }" 
-                            class="module-link"><i class="icon icon_3"></i>抄送我的</router-link>
-            </div>
-        </section> -->
+                            class="module-link"><i class="icon icon_3"></i>抄送我的</router-link> -->
+      </div>
+    </section>
     <section class="module m-shadow">
       <h2 class="title">业务申请</h2>
       <div class="module-item">
-        <router-link :to="{ path: '/leave' }"
-                     class="module-link"><i class="icon icon_4"></i>课程请假</router-link>
-        <router-link :to="{ path: '/periodadjust' }"
-                     class="module-link"><i class="icon icon_5"></i>课时调整</router-link>
-        <router-link :to="{ path: '/VIPApply' }"
-                     class="module-link"><i class="icon icon_6"></i>VIP申请</router-link>
+        <router-link :to="{ path: '/leave' }" class="module-link"
+          ><i class="icon icon_4"></i>课程请假</router-link
+        >
+        <router-link :to="{ path: '/periodadjust' }" class="module-link"
+          ><i class="icon icon_5"></i>课时调整</router-link
+        >
+        <router-link :to="{ path: '/VIPApply' }" class="module-link"
+          ><i class="icon icon_6"></i>VIP申请</router-link
+        >
       </div>
     </section>
 
@@ -29,34 +33,34 @@
       <h2 class="title">教学</h2>
       <div class="module-item">
         <!-- <span class="module-link"><i class="icon icon_7"></i>作业列表</span> -->
-        <router-link class="module-link"
-                     :to="{ path: '/tobeReport' }"><i class="icon icon_8"></i>待完成月报</router-link>
-        <router-link class="module-link"
-                     :to="{ path: '/manageEvaluation' }"><i class="icon icon_evaluate"></i>线上课评价</router-link>
-        <router-link class="module-link"
-                     :to="{ path: '/visitList' }"><i class="icon icon_visited"></i>回访记录</router-link>
+        <router-link class="module-link" :to="{ path: '/tobeReport' }"
+          ><i class="icon icon_8"></i>待完成月报</router-link
+        >
+        <router-link class="module-link" :to="{ path: '/manageEvaluation' }"
+          ><i class="icon icon_evaluate"></i>线上课评价</router-link
+        >
+        <router-link class="module-link" :to="{ path: '/visitList' }"
+          ><i class="icon icon_visited"></i>回访记录</router-link
+        >
       </div>
     </section>
-
   </div>
 </template>
 <script>
-import MHeader from '@/components/MHeader'
+import MHeader from "@/components/MHeader";
 export default {
-  name: 'business',
+  name: "business",
   components: { MHeader },
-  data () {
+  data() {
     return {
       userId: this.$route.params.userId,
-      dataInfo: null
-    }
-  },
-  mounted () {
-
+      dataInfo: null,
+    };
   },
-}
+  mounted() {},
+};
 </script>
-<style lang='less' scoped>
+<style lang="less" scoped>
 @import url("../../assets/commonLess/variable.less");
 .business {
   min-height: 100vh;
@@ -142,4 +146,4 @@ section,
     background-size: contain;
   }
 }
-</style>
+</style>