Explorar el Código

feat: 新增工作文档、应用管理和培训绩效模块

feat(用户管理): 添加团队协作功能

feat(考勤记录): 增加班组和科室名称查询条件

feat(上岗记录): 优化离岗时间显示和查询逻辑

feat(检查记录): 添加日期范围查询功能

feat(违禁品记录): 增加流程状态显示和日期范围查询

feat(文件上传): 支持拖拽上传和限制上传数量

fix(编辑器): 修正图片上传路径问题

fix(登录页): 移除默认账号密码

style(用户选择组件): 优化样式和回显逻辑

chore: 添加Vite插件配置和依赖

refactor(请求): 添加请求头标识

docs: 更新相关API文档
huoyi hace 4 meses
padre
commit
a1fc0edab4

+ 28 - 0
src/api/examManage/trainingPerformance.js

@@ -0,0 +1,28 @@
1
+import request from '@/utils/request'
2
+
3
+// 查询培训绩效列表
4
+export function getGrowthList(query) {
5
+  return request({
6
+    url: '/system/growth/list',
7
+    method: 'get',
8
+    params: query
9
+  })
10
+}
11
+
12
+///导入数据
13
+export function importData(data) {
14
+  return request({
15
+    url: '/system/growth/importData',
16
+    method: 'post',
17
+    data: data
18
+  })
19
+}
20
+
21
+//下载模板
22
+export function downloadTemplate() {
23
+  return request({
24
+    url: '/system/growth/importTemplate',
25
+    method: 'get',
26
+    responseType: 'blob'
27
+  })
28
+}

+ 43 - 0
src/api/system/app.js

@@ -0,0 +1,43 @@
1
+import request from '@/utils/request'
2
+
3
+// 查询应用列表
4
+export function listApp(query) {
5
+    return request({
6
+        url: '/system/app/list',
7
+        method: 'get',
8
+        params: query
9
+    })
10
+}
11
+//获取应用详细信息
12
+export function getApp(id) {
13
+    return request({
14
+        url: '/system/app/' + id,
15
+        method: 'get'
16
+    })
17
+}
18
+//新增应用
19
+export function addApp(data) {
20
+    return request({
21
+        url: '/system/app',
22
+        method: 'post',
23
+        data: data
24
+    })
25
+}
26
+//修改应用
27
+export function updateApp(data) {
28
+    return request({
29
+        url: '/system/app',
30
+        method: 'put',
31
+        data: data
32
+    })
33
+}
34
+//删除应用
35
+export function deleteApp(id) {
36
+    return request({
37
+        url: '/system/app/' + id,
38
+        method: 'delete'
39
+    })
40
+}
41
+
42
+
43
+

+ 15 - 0
src/api/system/role.js

@@ -117,3 +117,18 @@ export function deptTreeSelect(roleId) {
117 117
     method: 'get'
118 118
   })
119 119
 }
120
+
121
+//查询全部应用列表
122
+export function listAllApp() {
123
+  return request({
124
+    url: '/system/app/listAll',
125
+    method: 'get'
126
+  })
127
+}
128
+//根据角色ID查询应用列表
129
+export function listAppByRoleId(roleId) {
130
+  return request({
131
+    url: '/system/app/roleAppSelect/' + roleId,
132
+    method: 'get'
133
+  })
134
+}

+ 9 - 0
src/api/system/user.js

@@ -36,6 +36,15 @@ export function updateUser(data) {
36 36
   })
37 37
 }
38 38
 
39
+// 查询所有用户
40
+export function listAllUser(query) {
41
+  return request({
42
+    url: '/system/user/listAll',
43
+    method: 'get',
44
+    params: query
45
+  })
46
+}
47
+
39 48
 // 删除用户
40 49
 export function delUser(userId) {
41 50
   return request({

+ 41 - 0
src/api/system/workDocu.js

@@ -0,0 +1,41 @@
1
+import request from '@/utils/request'
2
+
3
+// 查询工作文档列表
4
+export function listWorkDocu(query) {
5
+    return request({
6
+        url: '/system/workingDocument/list',
7
+        method: 'get',
8
+        params: query
9
+    })
10
+}
11
+
12
+// 新增工作文档
13
+export function addWorkDocu(data) {
14
+    return request({
15
+        url: '/system/workingDocument',
16
+        method: 'post',
17
+        data: data
18
+    })
19
+}
20
+//修改工作文档
21
+export function updateWorkDocu(data) {
22
+    return request({
23
+        url: '/system/workingDocument',
24
+        method: 'put',
25
+        data: data
26
+    })
27
+}
28
+//删除工作文档
29
+export function deleteWorkDocu(id) {
30
+    return request({
31
+        url: '/system/workingDocument/' + id,
32
+        method: 'delete'
33
+    })
34
+}
35
+//获取工作文档详细信息
36
+export function getWorkDocu(id) {
37
+    return request({
38
+        url: '/system/workingDocument/' + id,
39
+        method: 'get'
40
+    })
41
+}

+ 2 - 1
src/components/Editor/index.vue

@@ -158,7 +158,8 @@ function handleUploadSuccess(res, file) {
158 158
     // 获取光标位置
159 159
     let length = quill.selection.savedRange.index
160 160
     // 插入图片,res.url为服务器返回的图片链接地址
161
-    quill.insertEmbed(length, "image", import.meta.env.VITE_APP_BASE_API + res.fileName)
161
+    // quill.insertEmbed(length, "image", import.meta.env.VITE_APP_BASE_API + res.fileName)
162
+    quill.insertEmbed(length, "image", res.url)
162 163
     // 调整光标到最后
163 164
     quill.setSelection(length + 1)
164 165
   } else {

+ 12 - 3
src/components/FileUpload/index.vue

@@ -15,9 +15,18 @@
15 15
       class="upload-file-uploader"
16 16
       ref="fileUpload"
17 17
       v-if="!disabled"
18
+      :drag="drag"
18 19
     >
19
-      <!-- 上传按钮 -->
20
-      <el-button type="primary">选取文件</el-button>
20
+      <!-- 根据drag属性条件渲染不同的上传界面 -->
21
+      <template v-if="drag">
22
+        <!-- <div class="el-upload-dragger"> -->
23
+          <i class="el-icon-upload"></i>
24
+          <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
25
+        <!-- </div> -->
26
+      </template>
27
+      <template v-else>
28
+        <el-button type="primary">选取文件</el-button>
29
+      </template>
21 30
     </el-upload>
22 31
     <!-- 上传提示 -->
23 32
     <div class="el-upload__tip" v-if="showTip && !disabled">
@@ -83,7 +92,7 @@ const props = defineProps({
83 92
   // 拖动排序
84 93
   drag: {
85 94
     type: Boolean,
86
-    default: true
95
+    default: false
87 96
   }
88 97
 })
89 98
 

+ 60 - 24
src/components/UserSelect/index.vue

@@ -1,24 +1,9 @@
1 1
 <template>
2 2
   <div class="flex flex-wrap">
3
-    <el-select
4
-      v-model="selectedValue"
5
-      filterable
6
-      remote
7
-      reserve-keyword
8
-      placeholder="请输入用户名"
9
-      :remote-method="debouncedRemoteMethod"
10
-      :loading="loading"
11
-      :multiple="multiple"
12
-      :disabled="disabled"
13
-      :style="{ width: width }"
14
-      clearable
15
-    >
16
-      <el-option
17
-        v-for="item in options"
18
-        :key="item.value"
19
-        :label="item.label"
20
-        :value="item.value"
21
-      />
3
+    <el-select v-model="selectedValue" filterable remote reserve-keyword :placeholder="placeholder"
4
+      :remote-method="debouncedRemoteMethod" :loading="loading" :multiple="multiple" :disabled="disabled"
5
+      :style="{ width: width }" :multiple-limit="max" clearable>
6
+      <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
22 7
     </el-select>
23 8
   </div>
24 9
 </template>
@@ -26,7 +11,8 @@
26 11
 <script lang="ts" setup>
27 12
 import { onMounted, ref, watch, defineProps, defineEmits, onUnmounted } from 'vue'
28 13
 import { debounce } from 'lodash-es'
29
-import { listUser } from "@/api/system/user"
14
+import { listUser, getUser } from "@/api/system/user"
15
+import { unref } from 'vue'
30 16
 
31 17
 interface ListItem {
32 18
   value: string
@@ -39,6 +25,8 @@ const props = defineProps<{
39 25
   multiple?: boolean
40 26
   disabled?: boolean
41 27
   width?: string
28
+  max?: number
29
+  placeholder?: string
42 30
 }>()
43 31
 
44 32
 // 定义组件事件
@@ -48,15 +36,33 @@ const options = ref<ListItem[]>([])
48 36
 const loading = ref(false)
49 37
 const selectedValue = ref<string | string[]>(props.modelValue)
50 38
 
39
+// 根据用户ID列表获取用户信息
40
+const fetchUsersByIds = async (userIds: string[]) => {
41
+  if (!userIds || userIds.length === 0) return []
42
+  try {
43
+    // 使用Promise.all并行获取每个用户的信息
44
+    const userPromises = userIds.map(userId => getUser(userId))
45
+    const userResponses = await Promise.all(userPromises)
46
+
47
+    return userResponses.map((response: any) => ({
48
+      value: response.data.userId,
49
+      label: response.data.nickName
50
+    }))
51
+  } catch (error) {
52
+    console.error('获取用户信息失败:', error)
53
+    return []
54
+  }
55
+}
56
+
51 57
 // 远程搜索方法
52 58
 const remoteMethod = async (query: string) => {
53 59
   if (query) {
54 60
     loading.value = true
55 61
     try {
56 62
       // 调用远程接口获取数据
57
-      const response = await listUser({ nickName: query }) 
63
+      const response = await listUser({ nickName: query })
58 64
       // 假设接口返回的数据结构为 { data: [...] },根据实际情况调整
59
-      options.value = response.rows.map((item) => ({ 
65
+      options.value = response.rows.map((item) => ({
60 66
         value: item.userId, // 根据实际接口返回字段调整
61 67
         label: item.nickName // 根据实际接口返回字段调整
62 68
       }))
@@ -73,9 +79,33 @@ const remoteMethod = async (query: string) => {
73 79
 // 防抖处理远程搜索
74 80
 const debouncedRemoteMethod = debounce(remoteMethod, 300)
75 81
 
82
+// 标记是否正在初始化回显,避免循环更新
83
+const isInitializing = ref(false)
84
+
85
+// 监听modelValue变化,有值时执行回显逻辑
86
+watch(() => props.modelValue, async (newValue, oldValue) => {
87
+  // 只有当值从无到有或值发生变化时才执行回显
88
+  if (newValue && newValue.length > 0 && newValue !== oldValue) {
89
+    isInitializing.value = true
90
+    try {
91
+      const userIds = Array.isArray(newValue) ? newValue : [newValue]
92
+      const userOptions = await fetchUsersByIds(userIds)
93
+      options.value = userOptions
94
+      
95
+      // 设置选中值,但不触发更新事件
96
+      selectedValue.value = newValue
97
+    } finally {
98
+      isInitializing.value = false
99
+    }
100
+  }
101
+}, { immediate: true })
102
+
76 103
 // 监听选中值变化并触发更新事件
77 104
 watch(selectedValue, (newValue) => {
78
-  emits('update:modelValue', newValue)
105
+  // 只有在非初始化状态下才触发更新事件
106
+  if (!isInitializing.value) {
107
+    emits('update:modelValue', newValue)
108
+  }
79 109
 })
80 110
 
81 111
 // 组件销毁时清空数据
@@ -84,4 +114,10 @@ onUnmounted(() => {
84 114
   selectedValue.value = props.multiple ? [] : ''
85 115
   emits('update:modelValue', selectedValue.value)
86 116
 })
87
-</script>
117
+</script>
118
+
119
+<style scoped lang="scss">
120
+.flex {
121
+  width: 100%;
122
+}
123
+</style>

+ 2 - 1
src/utils/request.js

@@ -11,7 +11,8 @@ let downloadLoadingInstance
11 11
 // 是否显示重新登录
12 12
 export let isRelogin = { show: false }
13 13
 
14
-axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'
14
+axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8';
15
+axios.defaults.headers['X-Request-Source'] = 'web';
15 16
 // 创建axios实例
16 17
 const service = axios.create({
17 18
   // axios中请求配置有baseURL选项,表示请求URL公共部分

+ 18 - 0
src/views/attendance/checkRecord/index.vue

@@ -9,6 +9,22 @@
9 9
           @keyup.enter="handleQuery"
10 10
         />
11 11
       </el-form-item>
12
+      <el-form-item label="班组名称" prop="teamName">
13
+        <el-input
14
+          v-model="queryParams.teamName"
15
+          placeholder="请输入班组名称"
16
+          clearable
17
+          @keyup.enter="handleQuery"
18
+        />
19
+      </el-form-item>
20
+      <el-form-item label="科室名称" prop="departmentName">
21
+        <el-input
22
+          v-model="queryParams.departmentName"
23
+          placeholder="请输入科室名称"
24
+          clearable
25
+          @keyup.enter="handleQuery"
26
+        />
27
+      </el-form-item>
12 28
       <el-form-item label="打卡日期">
13 29
         <el-date-picker
14 30
           clearable
@@ -56,6 +72,8 @@
56 72
 
57 73
     <el-table v-loading="loading" :data="checkRecordList" @selection-change="handleSelectionChange">
58 74
       <el-table-column label="打卡人姓名" align="center" prop="userName" />
75
+      <el-table-column label="班组名称" align="center" prop="teamName" />
76
+      <el-table-column label="科室名称" align="center" prop="departmentName" />
59 77
       <el-table-column label="打卡类型" align="center" prop="checkInTypeDesc" />
60 78
       <el-table-column label="打卡时间" align="center" prop="checkInTime" />
61 79
       <el-table-column label="备注" align="center" prop="remark" />

+ 16 - 5
src/views/attendance/postRecord/index.vue

@@ -60,14 +60,14 @@
60 60
           @keyup.enter="handleQuery"
61 61
         />
62 62
       </el-form-item>
63
-      <el-form-item label="岗位名称" prop="positionName">
63
+      <!-- <el-form-item label="岗位名称" prop="positionName">
64 64
         <el-input
65 65
           v-model="queryParams.positionName"
66 66
           placeholder="请输入岗位名称"
67 67
           clearable
68 68
           @keyup.enter="handleQuery"
69 69
         />
70
-      </el-form-item>
70
+      </el-form-item> -->
71 71
       <el-form-item>
72 72
         <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
73 73
         <el-button icon="Refresh" @click="resetQuery">重置</el-button>
@@ -116,12 +116,17 @@
116 116
       <el-table-column label="科室名称" align="center" prop="attendanceDepartmentName" width="80" />
117 117
       <el-table-column label="考勤日期" align="center" prop="attendanceDate" width="100" />
118 118
       <el-table-column label="上岗时间" align="center" prop="checkInTime" width="155" />
119
-      <el-table-column label="离岗时间" align="center" prop="checkOutTime" width="155" />
119
+      <el-table-column label="离岗时间" align="center" prop="checkOutTime" width="155" >
120
+        <template #default="scope">
121
+          {{ scope.row.checkOutTime=='2000-01-01 00:00:00'?'':scope.row.checkOutTime }}
122
+        </template>
123
+      </el-table-column>
120 124
       <el-table-column label="工作时长(分钟)" align="center" prop="workDuration" width="115" />
121 125
       <el-table-column label="航站楼名称" align="center" prop="terminlName" width="110" />
122 126
       <el-table-column label="区域名称" align="center" prop="regionalName" width="110" />
123 127
       <el-table-column label="通道名称" align="center" prop="channelName" width="110" />
124
-      <el-table-column label="岗位名称" align="center" prop="positionName" width="110" />
128
+
129
+      <!-- <el-table-column label="岗位名称" align="center" prop="positionName" width="110" /> -->
125 130
       <el-table-column label="备注" align="center" prop="remark" />
126 131
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="140">
127 132
         <template #default="scope">
@@ -392,7 +397,13 @@ const { queryParams, form, rules } = toRefs(data)
392 397
 /** 查询上岗记录列表 */
393 398
 function getList() {
394 399
   loading.value = true
395
-  listPostRecord(proxy.addDateRange(queryParams.value, dateRange.value)).then(response => {
400
+  let params = {
401
+    ...queryParams.value,
402
+    beginTime: dateRange.value[0],
403
+    endTime: dateRange.value[1],
404
+    // ...proxy.addDateRange(queryParams.value, dateRange.value)
405
+  }
406
+  listPostRecord(params).then(response => {
396 407
     postRecordList.value = response.rows
397 408
     total.value = response.total
398 409
     loading.value = false

+ 44 - 37
src/views/check/checkCorrection/index.vue

@@ -2,28 +2,29 @@
2 2
   <div class="app-container">
3 3
     <el-form :model="queryParams" ref="queryRef" :inline="true" label-width="100px">
4 4
       <el-row :gutter="16">
5
-        <el-col :span="8">
6
-          <el-form-item label="任务标题" prop="taskName">
7
-            <el-input v-model="queryParams.taskName" placeholder="请输入任务标题" clearable style="width: 200px;" />
8
-          </el-form-item>
9
-        </el-col>
10
-        <el-col :span="8">
11
-          <el-form-item label="检查人" prop="checkerName">
12
-            <el-input v-model="queryParams.checkerName" placeholder="请输入检查人" clearable style="width: 200px;" />
13
-          </el-form-item>
14
-        </el-col>
15
-        <el-col :span="8">
16
-          <el-form-item label="检查时间" prop="checkTime">
17
-            <el-date-picker v-model="queryParams.checkTime" type="date" value-format="YYYY-MM-DD" placeholder="请选择检查时间"
18
-              style="width: 200px;" clearable />
19
-          </el-form-item>
20
-        </el-col>
21
-        <el-col :span="24">
22
-          <el-form-item>
23
-            <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
24
-            <el-button icon="Refresh" @click="resetQuery">重置</el-button>
25
-          </el-form-item>
26
-        </el-col>
5
+
6
+        <el-form-item label="任务标题" prop="taskName">
7
+          <el-input v-model="queryParams.taskName" placeholder="请输入任务标题" clearable style="width: 200px;" />
8
+        </el-form-item>
9
+
10
+
11
+        <el-form-item label="检查人" prop="checkerName">
12
+          <el-input v-model="queryParams.checkerName" placeholder="请输入检查人" clearable style="width: 200px;" />
13
+        </el-form-item>
14
+
15
+
16
+        <el-form-item label="检查时间" prop="checkTime">
17
+          <el-date-picker clearable v-model="dateRange" value-format="YYYY-MM-DD" type="daterange" range-separator="-"
18
+            start-placeholder="开始日期" end-placeholder="结束日期">
19
+          </el-date-picker>
20
+        </el-form-item>
21
+
22
+
23
+        <el-form-item>
24
+          <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
25
+          <el-button icon="Refresh" @click="resetQuery">重置</el-button>
26
+        </el-form-item>
27
+
27 28
       </el-row>
28 29
     </el-form>
29 30
 
@@ -32,34 +33,33 @@
32 33
       <el-table-column label="任务标题" align="center" prop="taskName" />
33 34
       <el-table-column label="检查人" align="center" prop="checkerName" width="100" />
34 35
       <el-table-column label="检查时间" align="center" prop="checkTime" width="180">
35
-        <template #default=" scope ">
36
-          <span>{{ parseTime( scope.row.checkTime, '{y}-{m}-{d}' ) }}</span>
36
+        <template #default="scope">
37
+          <span>{{ parseTime(scope.row.checkTime, '{y}-{m}-{d}') }}</span>
37 38
         </template>
38 39
       </el-table-column>
39 40
       <el-table-column label="被检查级别" align="center" prop="checkedLevel" width="100">
40
-        <template #default=" scope ">
41
+        <template #default="scope">
41 42
           <dict-tag :options="check_checked_level" :value="scope.row.checkedLevel" />
42 43
         </template>
43 44
       </el-table-column>
44 45
       <el-table-column label="被检查人/班组/科" align="center" prop="checkedLevel">
45
-        <template #default=" scope ">
46
-          <div v-if=" scope.row.checkedLevel === 'DEPARTMENT_LEVEL' ">{{ scope.row.checkedDepartmentName }}</div>
47
-          <div v-if=" scope.row.checkedLevel === 'TEAM_LEVEL' ">{{ scope.row.checkedTeamName }}</div>
48
-          <div v-if=" scope.row.checkedLevel === 'PERSONNEL_LEVEL' ">{{ scope.row.checkedPersonnelName }}</div>
46
+        <template #default="scope">
47
+          <div v-if="scope.row.checkedLevel === 'DEPARTMENT_LEVEL'">{{ scope.row.checkedDepartmentName }}</div>
48
+          <div v-if="scope.row.checkedLevel === 'TEAM_LEVEL'">{{ scope.row.checkedTeamName }}</div>
49
+          <div v-if="scope.row.checkedLevel === 'PERSONNEL_LEVEL'">{{ scope.row.checkedPersonnelName }}</div>
49 50
         </template>
50 51
       </el-table-column>
51 52
       <el-table-column label="整改状态" align="center" prop="statusDesc" width="100" />
52 53
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="100">
53
-        <template #default=" scope ">
54
-          <el-button link type="info" icon="View" @click="handleDetail( scope.row )"
55
-            v-hasPermi="[ 'check:checkRecord:query' ]">详情</el-button>
54
+        <template #default="scope">
55
+          <el-button link type="info" icon="View" @click="handleDetail(scope.row)"
56
+            v-hasPermi="['check:checkRecord:query']">详情</el-button>
56 57
         </template>
57 58
       </el-table-column>
58 59
     </el-table>
59 60
     <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
60
-      v-model:limit="queryParams.pageSize"
61
-      @pagination="getList" />
62
-    <Details v-model:show="show" :id="cellRecord.id"/>
61
+      v-model:limit="queryParams.pageSize" @pagination="getList" />
62
+    <Details v-model:show="show" :id="cellRecord.id" />
63 63
   </div>
64 64
 </template>
65 65
 
@@ -73,6 +73,7 @@ const { check_checked_level } = useDict('check_checked_level')
73 73
 const checkRecordList = ref([])
74 74
 const loading = ref(false)
75 75
 const total = ref(0)
76
+const dateRange = ref([])
76 77
 const queryParams = ref({
77 78
   taskName: undefined,
78 79
   checkerName: undefined,
@@ -82,9 +83,15 @@ const queryParams = ref({
82 83
 })
83 84
 
84 85
 /** 查询检查记录列表 */
85
-function getList () {
86
+function getList() {
86 87
   loading.value = true
87
-  checkCorrection(queryParams.value).then(response => {
88
+  let params = {
89
+    ...queryParams.value,
90
+    startDate: dateRange.value[0],
91
+    endDate: dateRange.value[1]
92
+  }
93
+
94
+  checkCorrection(params).then(response => {
88 95
     checkRecordList.value = response.rows
89 96
     total.value = response.total
90 97
   }).finally(() => {

+ 17 - 7
src/views/check/checkRecord/index.vue

@@ -33,8 +33,11 @@
33 33
       </el-form-item>
34 34
 
35 35
       <el-form-item label="检查时间" prop="checkTime">
36
-        <el-date-picker v-model="queryParams.checkTime" type="date" value-format="YYYY-MM-DD" placeholder="请选择检查时间"
37
-          style="width: 200px;" clearable />
36
+        <!-- <el-date-picker v-model="queryParams.checkTime" type="daterange" value-format="YYYY-MM-DD" placeholder="请选择检查时间"
37
+          style="width: 200px;" clearable /> -->
38
+        <el-date-picker clearable v-model="dateRange" value-format="YYYY-MM-DD" type="daterange" range-separator="-"
39
+          start-placeholder="开始日期" end-placeholder="结束日期">
40
+        </el-date-picker>
38 41
       </el-form-item>
39 42
       <!-- <el-form-item label="检查结果" prop="checkResult">
40 43
          <el-select v-model="queryParams.checkResult" placeholder="请选择检查结果" clearable style="width: 120px">
@@ -96,9 +99,9 @@
96 99
 
97 100
     <el-table v-loading="loading" :data="checkRecordList" @selection-change="handleSelectionChange">
98 101
       <el-table-column type="selection" width="55" align="center" />
99
-      <el-table-column label="任务编号" align="center" prop="taskCode" width="180"/>
102
+      <el-table-column label="任务编号" align="center" prop="taskCode" width="180" />
100 103
       <el-table-column label="任务标题" align="center" prop="taskName" />
101
-      <el-table-column label="检查人" align="center" prop="checkerName" width="100"/>
104
+      <el-table-column label="检查人" align="center" prop="checkerName" width="100" />
102 105
       <el-table-column label="检查时间" align="center" prop="checkTime" width="180">
103 106
         <template #default="scope">
104 107
           <span>{{ parseTime(scope.row.checkTime, '{y}-{m}-{d}') }}</span>
@@ -111,10 +114,10 @@
111 114
       </el-table-column>
112 115
       <el-table-column label="被检查人/班组/科" align="center" prop="checkedLevel">
113 116
         <template #default="scope">
114
-          <div v-if="scope.row.checkedLevel === 'DEPARTMENT_LEVEL'">{{ scope.row.checkedDepartmentName  }}</div>
117
+          <div v-if="scope.row.checkedLevel === 'DEPARTMENT_LEVEL'">{{ scope.row.checkedDepartmentName }}</div>
115 118
           <div v-if="scope.row.checkedLevel === 'TEAM_LEVEL'">{{ scope.row.checkedTeamName }}</div>
116 119
           <div v-if="scope.row.checkedLevel === 'PERSONNEL_LEVEL'">{{ scope.row.checkedPersonnelName }}</div>
117
-        </template>  
120
+        </template>
118 121
       </el-table-column>
119 122
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="100">
120 123
         <template #default="scope">
@@ -161,6 +164,7 @@ const total = ref(0)
161 164
 const title = ref("")
162 165
 const positiveList = ref([])
163 166
 const negativeList = ref([])
167
+const dateRange = ref([])
164 168
 
165 169
 const data = reactive({
166 170
   form: {},
@@ -200,7 +204,13 @@ const { queryParams, form } = toRefs(data)
200 204
 /** 查询检查记录列表 */
201 205
 function getList() {
202 206
   loading.value = true
203
-  listCheckRecord(queryParams.value).then(response => {
207
+  let params = {
208
+    ...queryParams.value,
209
+    startDate: dateRange.value[0],
210
+    endDate: dateRange.value[1]
211
+  }
212
+
213
+  listCheckRecord(params).then(response => {
204 214
     checkRecordList.value = response.rows
205 215
     total.value = response.total
206 216
     loading.value = false

+ 188 - 0
src/views/examManage/trainingPerformance/index.vue

@@ -0,0 +1,188 @@
1
+<template>
2
+  <div class="app-container">
3
+    <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch">
4
+      <el-form-item label="考试编号" prop="examCode">
5
+        <el-input v-model="queryParams.examCode" placeholder="请输入考试编号" clearable style="width: 200px" />
6
+      </el-form-item>
7
+      <el-form-item label="考试名称" prop="examName">
8
+        <el-input v-model="queryParams.examName" placeholder="请输入考试名称" clearable style="width: 200px" />
9
+      </el-form-item>
10
+      <el-form-item label="考试人姓名" prop="userName">
11
+        <el-input v-model="queryParams.userName" placeholder="请输入考试人姓名" clearable style="width: 200px" />
12
+      </el-form-item>
13
+      <el-form-item label="考试时间" prop="examTime">
14
+        <el-date-picker v-model="queryParams.examTime" type="daterange" range-separator="至" start-placeholder="开始日期"
15
+          end-placeholder="结束日期" value-format="YYYY-MM-DD" style="width: 240px" />
16
+      </el-form-item>
17
+      <el-form-item>
18
+        <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
19
+        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
20
+      </el-form-item>
21
+    </el-form>
22
+
23
+    <el-row :gutter="10" class="mb8">
24
+      <el-col :span="1.5">
25
+        <el-button type="info" plain icon="Upload" @click="handleImport">导入</el-button>
26
+      </el-col>
27
+      <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
28
+    </el-row>
29
+
30
+    <el-table v-loading="loading" :data="trainingPerformanceList" >
31
+      <el-table-column label="考试编号" align="center" prop="examCode"  />
32
+      <el-table-column label="考试名称" align="center" prop="examName"  />
33
+      <el-table-column label="考试人编号" align="center" prop="userCode" />
34
+      <el-table-column label="考试人姓名" align="center" prop="userName" />
35
+      <el-table-column label="考试时间" align="center" prop="examTime" >
36
+        <template #default="scope">
37
+          <span>{{ parseTime(scope.row.examTime, '{y}-{m}-{d}') }}</span>
38
+        </template>
39
+      </el-table-column>
40
+      <el-table-column label="考试成绩" align="center" prop="examScore"  />
41
+    </el-table>
42
+
43
+    <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
44
+      v-model:limit="queryParams.pageSize" @pagination="getList" />
45
+
46
+    <!-- 导入对话框 -->
47
+    <el-dialog :title="upload.title" v-model="upload.open" width="400px" append-to-body>
48
+      <el-upload ref="uploadRef" :limit="1" accept=".xlsx, .xls" :headers="upload.headers"
49
+        :action="upload.url + '?updateSupport=' + upload.updateSupport" :disabled="upload.isUploading"
50
+        :on-progress="handleFileUploadProgress" :on-success="handleFileSuccess" :auto-upload="false" drag>
51
+        <el-icon class="el-icon--upload"><upload-filled /></el-icon>
52
+        <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
53
+        <template #tip>
54
+          <div class="el-upload__tip text-center">
55
+              <span>仅允许导入xls、xlsx格式文件。</span>
56
+              <el-link type="primary" :underline="false" style="font-size:16px;vertical-align: baseline;" @click="handleDownloadTemplate">下载模板</el-link>
57
+            </div>
58
+        </template>
59
+      </el-upload>
60
+      <template #footer>
61
+        <div class="dialog-footer">
62
+          <el-button type="primary" @click="submitFileForm">确 定</el-button>
63
+          <el-button @click="upload.open = false">取 消</el-button>
64
+        </div>
65
+      </template>
66
+    </el-dialog>
67
+  </div>
68
+</template>
69
+
70
+<script setup name="TrainingPerformance">
71
+import { getGrowthList, importData, downloadTemplate } from "@/api/examManage/trainingPerformance"
72
+import { getToken } from "@/utils/auth"
73
+import { addDateRange, parseTime } from "@/utils/ruoyi"
74
+import { UploadFilled } from '@element-plus/icons-vue'
75
+
76
+const { proxy } = getCurrentInstance()
77
+
78
+const trainingPerformanceList = ref([])
79
+const loading = ref(true)
80
+const showSearch = ref(true)
81
+const ids = ref([])
82
+const single = ref(true)
83
+const multiple = ref(true)
84
+const total = ref(0)
85
+const dateRange = ref([])
86
+
87
+// 导入参数
88
+const upload = reactive({
89
+  // 是否显示弹出层
90
+  open: false,
91
+  // 弹出层标题
92
+  title: "",
93
+  // 是否禁用上传
94
+  isUploading: false,
95
+  // 是否更新已经存在的用户数据
96
+  updateSupport: 0,
97
+  // 设置上传的请求头部
98
+  headers: { Authorization: "Bearer " + getToken() },
99
+  // 上传的地址
100
+  url: import.meta.env.VITE_APP_BASE_API + "/system/growth/importData"
101
+})
102
+
103
+const data = reactive({
104
+  queryParams: {
105
+    pageNum: 1,
106
+    pageSize: 10,
107
+    examCode: undefined,
108
+    examName: undefined,
109
+    userName: undefined,
110
+    examTime: []
111
+  }
112
+})
113
+
114
+const { queryParams } = toRefs(data)
115
+
116
+/** 查询培训绩效列表 */
117
+function getList() {
118
+  loading.value = true;
119
+  let params = {
120
+    ...queryParams.value,
121
+    startTime: queryParams.value.examTime.length > 0 ? queryParams.value.examTime[0] : undefined,
122
+    endTime: queryParams.value.examTime.length > 0 ? queryParams.value.examTime[1] : undefined
123
+  }
124
+  delete params.examTime
125
+  getGrowthList(params).then(response => {
126
+    trainingPerformanceList.value = response.rows
127
+    total.value = response.total
128
+    loading.value = false
129
+  })
130
+}
131
+
132
+/** 搜索按钮操作 */
133
+function handleQuery() {
134
+  queryParams.value.pageNum = 1
135
+  getList()
136
+}
137
+
138
+/** 重置按钮操作 */
139
+function resetQuery() {
140
+  dateRange.value = []
141
+  proxy.resetForm("queryRef")
142
+  handleQuery()
143
+}
144
+
145
+/** 多选框选中数据 */
146
+function handleSelectionChange(selection) {
147
+  ids.value = selection.map(item => item.id)
148
+  single.value = selection.length != 1
149
+  multiple.value = !selection.length
150
+}
151
+
152
+/** 导入按钮操作 */
153
+function handleImport() {
154
+  upload.title = "导入"
155
+  upload.open = true
156
+}
157
+
158
+/** 下载模板操作 */
159
+function handleDownloadTemplate() {
160
+
161
+  proxy.download("/system/growth/importTemplate", {}, `record_template_${new Date().getTime()}.xlsx`)
162
+}
163
+
164
+/**文件上传中处理 */
165
+const handleFileUploadProgress = (event, file, fileList) => {
166
+  upload.isUploading = true
167
+}
168
+
169
+/** 文件上传成功处理 */
170
+const handleFileSuccess = (response, file, fileList) => {
171
+  upload.open = false
172
+  upload.isUploading = false
173
+  proxy.$refs["uploadRef"].handleRemove(file)
174
+  if (response.code === 200) {
175
+    proxy.$alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + "</div>", "导入结果", { dangerouslyUseHTMLString: true })
176
+    getList()
177
+  } else {
178
+    proxy.$modal.msgError(response.msg)
179
+  }
180
+}
181
+
182
+/** 提交上传文件 */
183
+function submitFileForm() {
184
+  proxy.$refs["uploadRef"].submit()
185
+}
186
+
187
+getList()
188
+</script>

+ 31 - 13
src/views/item/record/index.vue

@@ -7,8 +7,11 @@
7 7
       </el-form-item>
8 8
 
9 9
       <el-form-item label="查获时间" prop="seizureTime">
10
-        <el-date-picker clearable v-model="queryParams.seizureTime" type="date" value-format="YYYY-MM-DD"
11
-          placeholder="请选择查获时间">
10
+        <!-- <el-date-picker clearable v-model="queryParams.seizureTime" type="date" value-format="YYYY-MM-DD"
11
+          placeholder="请选择查获时间"> 
12
+        </el-date-picker>-->
13
+        <el-date-picker clearable v-model="dateRange" value-format="YYYY-MM-DD" type="daterange" range-separator="-"
14
+          start-placeholder="开始日期" end-placeholder="结束日期">
12 15
         </el-date-picker>
13 16
       </el-form-item>
14 17
 
@@ -77,6 +80,11 @@
77 80
       <el-table-column label="安检岗位" align="center" prop="checkMethodDesc" />
78 81
       <el-table-column label="查获班组" align="center" prop="inspectTeamName" />
79 82
       <el-table-column label="上报班组" align="center" prop="attendanceTeamName" />
83
+      <el-table-column label="流程状态" align="center" prop="processStatus" >
84
+        <template #default="scope">
85
+          <dict-tag :options="process_status" :value="scope.row.processStatus" />
86
+        </template>
87
+      </el-table-column>
80 88
       <!-- <el-table-column label="违禁品类型" align="center" prop="categoryNameTwo" />
81 89
       <el-table-column label="数量" align="center" prop="quantity" />
82 90
       <el-table-column label="查获部位" align="center" prop="customLocation" />
@@ -103,7 +111,9 @@
103 111
     <el-dialog :title="title" v-model="open" width="800px" append-to-body>
104 112
       <el-form ref="recordRef" :model="form" :rules="rules" label-width="9em" disabled>
105 113
         <el-form-item label="违禁品类别/类型" prop="channelCode">
106
-          <el-input :value="`${form.itemSeizureItemsList[0].categoryNameOne} / ${form.itemSeizureItemsList[0].categoryNameTwo}`" placeholder="- -" />
114
+          <el-input
115
+            :value="`${form.itemSeizureItemsList[0].categoryNameOne} / ${form.itemSeizureItemsList[0].categoryNameTwo}`"
116
+            placeholder="- -" />
107 117
         </el-form-item>
108 118
         <!-- <el-form-item label="违禁品名称" prop="channelCode">
109 119
           <el-input v-model="form.itemSeizureItemsList[0].itemName" placeholder="" />
@@ -112,11 +122,13 @@
112 122
         <el-form-item label="数量" prop="channelCode">
113 123
           <el-input v-model="form.itemSeizureItemsList[0].quantity" placeholder="-" />
114 124
         </el-form-item>
115
-         <!-- <el-form-item label="查获部位" prop="channelCode">
125
+        <!-- <el-form-item label="查获部位" prop="channelCode">
116 126
           <el-input v-model="form.itemSeizureItemsList[0].checkPositionNameOne" placeholder="" />
117 127
         </el-form-item> -->
118
-           <el-form-item label="部位类别/类型" prop="channelCode">
119
-          <el-input :value="`${form.itemSeizureItemsList[0].checkPositionNameOne} / ${form.itemSeizureItemsList[0].checkPositionNameTwo}`" placeholder="- -" />
128
+        <el-form-item label="部位类别/类型" prop="channelCode">
129
+          <el-input
130
+            :value="`${form.itemSeizureItemsList[0].checkPositionNameOne} / ${form.itemSeizureItemsList[0].checkPositionNameTwo}`"
131
+            placeholder="- -" />
120 132
         </el-form-item>
121 133
         <!-- <el-form-item label="具体位置" prop="channelCode">
122 134
           <el-input v-model="form.itemSeizureItemsList[0].checkPositionSpecific" placeholder="" />
@@ -125,7 +137,7 @@
125 137
           <el-input v-model="form.itemSeizureItemsList[0].handlingMethodDesc" placeholder="-" />
126 138
         </el-form-item>
127 139
         <el-form-item label="是否隐匿夹带" prop="channelCode">
128
-          <el-select v-model="form.itemSeizureItemsList[0].isActiveConcealment"  placeholder="-">
140
+          <el-select v-model="form.itemSeizureItemsList[0].isActiveConcealment" placeholder="-">
129 141
             <el-option label="否" :value="0" />
130 142
             <el-option label="是" :value="1" />
131 143
           </el-select>
@@ -139,7 +151,7 @@
139 151
         <el-form-item label="航班号" prop="passengerFlight">
140 152
           <el-input v-model="form.passengerFlight" placeholder="-" />
141 153
         </el-form-item> -->
142
-        
154
+
143 155
       </el-form>
144 156
       <template #footer>
145 157
         <div class="dialog-footer">
@@ -154,7 +166,7 @@
154 166
 <script setup name="Record">
155 167
 import { listRecord, getRecord, delRecord, addRecord, updateRecord } from "@/api/item/record"
156 168
 import { onMounted } from 'vue'
157
-
169
+import { useDict } from '@/utils/dict'
158 170
 const { proxy } = getCurrentInstance()
159 171
 
160 172
 const recordList = ref([])
@@ -166,7 +178,8 @@ const single = ref(true)
166 178
 const multiple = ref(true)
167 179
 const total = ref(0)
168 180
 const title = ref("")
169
-
181
+const dateRange = ref([])
182
+const { process_status } = useDict('process_status')
170 183
 const data = reactive({
171 184
   form: {},
172 185
   queryParams: {
@@ -276,8 +289,13 @@ const { queryParams, form, rules } = toRefs(data)
276 289
 
277 290
 /** 查询查获记录列表 */
278 291
 function getList() {
279
-  loading.value = true
280
-  listRecord(queryParams.value).then(response => {
292
+  loading.value = true;
293
+  let params = {
294
+    ...queryParams.value,
295
+    beginTime: dateRange.value[0],
296
+    endTime: dateRange.value[1]
297
+  }
298
+  listRecord(params).then(response => {
281 299
     recordList.value = response.rows
282 300
     total.value = response.total
283 301
     loading.value = false
@@ -319,7 +337,7 @@ function reset() {
319 337
     terminlName: null,
320 338
     passengerName: null,
321 339
     passengerGender: null,
322
-     itemSeizureItemsList: [{}],
340
+    itemSeizureItemsList: [{}],
323 341
     passengerCard: null,
324 342
     passengerFlight: null,
325 343
     inspectTeamId: null,

+ 3 - 3
src/views/login.vue

@@ -77,8 +77,8 @@ const router = useRouter()
77 77
 const { proxy } = getCurrentInstance()
78 78
 
79 79
 const loginForm = ref({
80
-  username: "admin",
81
-  password: "admin123",
80
+  username: "",
81
+  password: "",
82 82
   rememberMe: false,
83 83
   code: "",
84 84
   uuid: ""
@@ -160,7 +160,7 @@ function getCookie() {
160 160
 }
161 161
 
162 162
 getCode()
163
-getCookie()
163
+// getCookie()
164 164
 </script>
165 165
 
166 166
 <style lang='scss' scoped>

+ 482 - 0
src/views/system/app/index.vue

@@ -0,0 +1,482 @@
1
+<template>
2
+    <div class="app-container">
3
+        <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
4
+            <el-form-item label="应用名称" prop="appName">
5
+                <el-input v-model="queryParams.appName" placeholder="请输入应用名称" clearable @keyup.enter="handleQuery" />
6
+            </el-form-item>
7
+
8
+            <el-form-item label="创建者" prop="createBy">
9
+                <el-input v-model="queryParams.createBy" placeholder="请输入创建者" clearable @keyup.enter="handleQuery" />
10
+            </el-form-item>
11
+
12
+            <el-form-item label="状态" prop="status">
13
+                <el-select v-model="queryParams.status" placeholder="请选择状态" clearable style="width: 200px;">
14
+                    <el-option label="正常" :value="1" />
15
+                    <el-option label="关闭" :value="0" />
16
+                </el-select>
17
+            </el-form-item>
18
+
19
+            <el-form-item>
20
+                <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
21
+                <el-button icon="Refresh" @click="resetQuery">重置</el-button>
22
+            </el-form-item>
23
+        </el-form>
24
+
25
+        <el-row :gutter="10" class="mb8">
26
+            <el-col :span="1.5">
27
+                <el-button type="primary" plain icon="Plus" @click="handleAdd"
28
+                    v-hasPermi="['system:app:add']">新增</el-button>
29
+            </el-col>
30
+
31
+            <el-col :span="1.5">
32
+                <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete"
33
+                    v-hasPermi="['system:app:remove']">删除</el-button>
34
+            </el-col>
35
+            <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
36
+        </el-row>
37
+
38
+        <el-table v-loading="loading" :data="docList" @selection-change="handleSelectionChange" :row-key="getRowKey">
39
+            <el-table-column type="selection" width="55" align="center" />
40
+            <el-table-column type="index" label="序号" align="center" width="80" />
41
+            <el-table-column label="应用名称" align="center" prop="appName" />
42
+            <el-table-column label="显示顺序" align="center" prop="appSort" width="100" />
43
+            <el-table-column label="状态" align="center" prop="status">
44
+                <template #default="scope">
45
+                    <dict-tag :options="sys_normal_disable" :value="scope.row.status" />
46
+                </template>
47
+            </el-table-column>
48
+            <el-table-column label="创建者" align="center" prop="createBy" />
49
+            <el-table-column label="创建时间" align="center" prop="createTime" width="180">
50
+                <template #default="scope">
51
+                    <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
52
+                </template>
53
+            </el-table-column>
54
+            <el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width">
55
+                <template #default="scope">
56
+                    <el-tooltip content="修改" placement="top" v-hasPermi="['system:app:edit']">
57
+                        <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button>
58
+                    </el-tooltip>
59
+                    <el-tooltip content="删除" placement="top" v-hasPermi="['system:app:remove']">
60
+                        <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
61
+                    </el-tooltip>
62
+                </template>
63
+            </el-table-column>
64
+        </el-table>
65
+
66
+        <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
67
+            v-model:limit="queryParams.pageSize" @pagination="getList" />
68
+
69
+        <!-- 添加或修改应用管理对话框 -->
70
+        <el-dialog :title="title" v-model="open" width="700px" append-to-body destroy-on-close>
71
+            <el-form ref="docRef" :model="form" :rules="rules" label-width="9em">
72
+                <el-form-item label="应用名称" prop="appName">
73
+                    <el-input v-model="form.appName" placeholder="请输入应用名称" />
74
+                </el-form-item>
75
+                <el-form-item label="角色" prop="roleIds">
76
+                    <el-select v-model="form.roleIds" multiple placeholder="请选择角色" style="width: 100%;">
77
+                        <el-option v-for="role in roleOptions" :key="role.roleId" :label="role.roleName"
78
+                            :value="role.roleId" />
79
+                    </el-select>
80
+                </el-form-item>
81
+                <el-form-item label="链接" prop="appUrl">
82
+                    <el-input v-model="form.appUrl" placeholder="请输入应用链接" />
83
+                </el-form-item>
84
+                <el-form-item label="状态" prop="status">
85
+                    <el-radio-group v-model="form.status">
86
+                        <el-radio :label="'1'">正常</el-radio>
87
+                        <el-radio :label="'0'">关闭</el-radio>
88
+                    </el-radio-group>
89
+                </el-form-item>
90
+                <!-- <el-form-item label="是否为首页应用" prop="homePage">
91
+                    <el-radio-group v-model="form.homePage">
92
+                        <el-radio :label="'1'">是</el-radio>
93
+                        <el-radio :label="'0'">否</el-radio>
94
+                    </el-radio-group>
95
+                </el-form-item> -->
96
+                <el-form-item label="首页角色" prop="homeRoleIds">
97
+                    <el-select v-model="form.homeRoleIds" multiple placeholder="请选择角色" style="width: 100%;">
98
+                        <el-option v-for="role in roleOptions" :key="role.roleId" :label="role.roleName"
99
+                            :value="role.roleId" />
100
+                    </el-select>
101
+                </el-form-item>
102
+                <el-form-item label="显示顺序" prop="appSort">
103
+                    <el-input-number v-model="form.appSort" :min="1" :max="999" controls-position="right"
104
+                        placeholder="请输入显示顺序" />
105
+                </el-form-item>
106
+                <el-form-item label="图标" prop="workbenchIcon">
107
+                    <el-upload ref="iconUploadRef" :limit="1" accept="image/*" :headers="upload.headers"
108
+                        :action="upload.url" :file-list="upload.iconFileList" :disabled="false"
109
+                        :on-success="handleIconSuccess" :on-remove="handleIconRemove" :auto-upload="true"
110
+                        list-type="picture-card">
111
+                        <el-icon class="avatar-uploader-icon">
112
+                            <plus />
113
+                        </el-icon>
114
+                        <template #tip>
115
+                            <div class="el-upload__tip">请上传图标,建议尺寸 64x64px</div>
116
+                        </template>
117
+                    </el-upload>
118
+                </el-form-item>
119
+
120
+
121
+            </el-form>
122
+            <template #footer>
123
+                <div class="dialog-footer">
124
+                    <el-button @click="cancel">取 消</el-button>
125
+                    <el-button type="primary" @click="submitForm">确 定</el-button>
126
+                </div>
127
+            </template>
128
+        </el-dialog>
129
+    </div>
130
+</template>
131
+
132
+<script setup name="App">
133
+import { onMounted, ref, reactive, toRefs, computed } from 'vue'
134
+import { ElMessage } from 'element-plus'
135
+import { UploadFilled, Plus } from '@element-plus/icons-vue'
136
+import Pagination from '@/components/Pagination/index.vue'
137
+import RightToolbar from '@/components/RightToolbar/index.vue'
138
+import { parseTime } from '@/utils/ruoyi'
139
+import { getToken } from '@/utils/auth'
140
+import { listApp, getApp, deleteApp, addApp, updateApp } from '@/api/system/app'
141
+import { listRole } from '@/api/system/role'
142
+const { proxy } = getCurrentInstance()
143
+
144
+// 使用真实API接口,已从@/api/system/workDocu导入
145
+const sys_normal_disable = [
146
+    { label: '正常', value: '1' },
147
+    { label: '关闭', value: '0' }
148
+]
149
+
150
+const getRowKey = (row) => {
151
+    return row.appId
152
+}
153
+
154
+// 表格数据
155
+const docList = ref([])
156
+const open = ref(false)
157
+const loading = ref(true)
158
+const showSearch = ref(true)
159
+const ids = ref([])
160
+const single = ref(true)
161
+const multiple = ref(true)
162
+const total = ref(0)
163
+const title = ref('')
164
+
165
+// 角色选项
166
+const roleOptions = ref([])
167
+
168
+// 上传相关
169
+
170
+const iconUploadRef = ref(null)
171
+
172
+
173
+const upload = reactive({
174
+
175
+    iconFileList: [],
176
+
177
+    // 是否显示弹出层
178
+    open: false,
179
+    // 弹出层标题
180
+    title: "",
181
+    // 是否禁用上传
182
+    isUploading: false,
183
+    // 是否更新已经存在的用户数据
184
+    updateSupport: 0,
185
+    // 设置上传的请求头部
186
+    headers: { Authorization: "Bearer " + getToken() },
187
+    // 上传的地址
188
+    url: import.meta.env.VITE_APP_BASE_API + "/common/upload"
189
+})
190
+
191
+
192
+
193
+
194
+const handleIconSuccess = (response, file, fileList) => {
195
+    if (response.code === 200) {
196
+        form.value.workbenchIcon = response.url
197
+        ElMessage.success('图标上传成功')
198
+    } else {
199
+        ElMessage.error(response.msg || '图标上传失败')
200
+    }
201
+}
202
+
203
+
204
+// 图标移除处理
205
+const handleIconRemove = (file, fileList) => {
206
+    form.value.workbenchIcon = '';
207
+}
208
+
209
+
210
+
211
+
212
+
213
+
214
+// 表单数据
215
+const data = reactive({
216
+    form: {
217
+        appId: null,
218
+        appName: '',
219
+        roleIds: [],
220
+        homeRoleIds: [],
221
+        appUrl: '',
222
+        status: '1',
223
+        // homePage: '0',
224
+        workbenchIcon: '',
225
+        homeChart: '',
226
+        appFile: '',
227
+        appSort: 1
228
+
229
+    },
230
+    queryParams: {
231
+        pageNum: 1,
232
+        pageSize: 10,
233
+        appName: '',
234
+        createBy: '',
235
+        status: null
236
+    },
237
+    rules: {
238
+        appName: [
239
+            { required: true, message: '应用名称不能为空', trigger: 'blur' }
240
+        ],
241
+        appSort: [
242
+            { required: true, message: '请输入显示顺序', trigger: 'blur' }
243
+        ],
244
+        workbenchIcon: [
245
+            { required: true, message: '请上传图标', trigger: 'change' }
246
+        ],
247
+    }
248
+})
249
+
250
+const { queryParams, form, rules } = toRefs(data)
251
+
252
+/** 查询应用列表 */
253
+const getList = () => {
254
+    loading.value = true
255
+    listApp(queryParams.value).then(response => {
256
+        docList.value = response.rows
257
+        total.value = response.total
258
+        loading.value = false
259
+    })
260
+}
261
+
262
+// 取消按钮
263
+const cancel = () => {
264
+    open.value = false
265
+    reset()
266
+}
267
+
268
+// 表单重置
269
+const reset = () => {
270
+    form.value = {
271
+        appId: null,
272
+        appName: '',
273
+        roleIds: [],
274
+        homeRoleIds: [],
275
+        appUrl: '',
276
+        status: '1',
277
+        // homePage: '0',
278
+        workbenchIcon: '',
279
+        homeChart: '',
280
+        appFile: '',
281
+        appSort: 1
282
+    }
283
+    // 清空文件列表
284
+
285
+    upload.iconFileList = []
286
+
287
+    if (proxy?.$refs?.docRef) {
288
+        proxy.$refs.docRef.resetFields()
289
+    }
290
+}
291
+
292
+/** 搜索按钮操作 */
293
+const handleQuery = () => {
294
+    queryParams.value.pageNum = 1
295
+    getList()
296
+}
297
+
298
+/** 重置按钮操作 */
299
+const resetQuery = () => {
300
+    if (proxy?.$refs?.queryRef) {
301
+        proxy.$refs.queryRef.resetFields()
302
+    }
303
+    handleQuery()
304
+}
305
+
306
+///** 多选框选中数据 */
307
+const handleSelectionChange = (selection) => {
308
+    ids.value = selection.map(item => item.appId)
309
+    single.value = selection.length != 1
310
+    multiple.value = !selection.length
311
+}
312
+
313
+/** 新增按钮操作 */
314
+const handleAdd = () => {
315
+    reset()
316
+    open.value = true
317
+    title.value = '添加工作文档'
318
+}
319
+
320
+/** 修改按钮操作 */
321
+const handleUpdate = (row) => {
322
+    reset()
323
+
324
+    const _id = row?.appId || ids.value
325
+    getApp(_id).then(response => {
326
+        form.value = response.data;
327
+
328
+
329
+        if (response.data.sysRoleList) {
330
+            form.value.roleIds = response.data.sysRoleList.map(item => item.roleId)
331
+
332
+        }
333
+        if (response.data.homePageSysRoleList) {
334
+            form.value.homeRoleIds = response.data.homePageSysRoleList.map(item => item.roleId)
335
+        }
336
+
337
+        if (response.data.workbenchIcon) {
338
+            upload.iconFileList = [{
339
+                name: '',
340
+                url: response.data.workbenchIcon
341
+            }]
342
+        }
343
+
344
+
345
+
346
+        open.value = true
347
+        title.value = '修改应用管理'
348
+    })
349
+}
350
+
351
+/** 提交按钮 */
352
+const submitForm = () => {
353
+    if (proxy?.$refs?.docRef) {
354
+        proxy.$refs.docRef.validate((valid) => {
355
+            if (valid) {
356
+                let sysRoleList = roleOptions.value.filter(item => form.value.roleIds.includes(item.roleId))
357
+                let homePageSysRoleList = roleOptions.value.filter(item => form.value.homeRoleIds.includes(item.roleId))
358
+                let params = {
359
+                    ...form.value,
360
+                        sysRoleList: sysRoleList,
361
+                        homePageSysRoleList: homePageSysRoleList
362
+                }
363
+                if (form.value.appId != undefined) {
364
+                    updateApp(params).then(response => {
365
+                        ElMessage.success('修改成功')
366
+                        open.value = false
367
+                        getList()
368
+                    })
369
+                } else {
370
+                    addApp(params).then(response => {
371
+                        ElMessage.success('新增成功')
372
+                        open.value = false
373
+                        getList()
374
+                    })
375
+                }
376
+            }
377
+        })
378
+    }
379
+}
380
+
381
+/** 删除按钮操作 */
382
+const handleDelete = (row) => {
383
+    const _ids = row?.appId || ids.value;
384
+
385
+    // 检查是否有要删除的ID
386
+    if (!_ids || (Array.isArray(_ids) && _ids.length === 0)) {
387
+        ElMessage.warning('请选择要删除的数据项')
388
+        return
389
+    }
390
+
391
+    if (proxy?.$modal) {
392
+        proxy.$modal.confirm('是否确认删除数据项?').then(() => {
393
+            const deleteIds = Array.isArray(_ids) ? _ids.join(',') : _ids
394
+            return deleteApp(deleteIds)
395
+        }).then(() => {
396
+            getList()
397
+            ElMessage.success('删除成功')
398
+        }).catch((error) => {
399
+            console.error('删除失败:', error)
400
+            ElMessage.error('删除失败')
401
+        })
402
+    }
403
+}
404
+
405
+// 获取角色列表
406
+const getRoleList = () => {
407
+    listRole().then(response => {
408
+        roleOptions.value = response.rows || []
409
+    })
410
+}
411
+
412
+// 页面加载时获取数据
413
+onMounted(() => {
414
+    getList()
415
+    getRoleList()
416
+})
417
+</script>
418
+
419
+<style scoped>
420
+.app-container {
421
+    padding: 20px;
422
+}
423
+
424
+.mb8 {
425
+    margin-bottom: 8px;
426
+}
427
+
428
+.fixed-width {
429
+    width: 140px;
430
+}
431
+
432
+.small-padding .cell {
433
+    padding: 10px 5px;
434
+}
435
+
436
+.dialog-footer {
437
+    text-align: right;
438
+}
439
+
440
+/* 图片上传预览样式 */
441
+.avatar {
442
+    width: 100px;
443
+    height: 100px;
444
+    object-fit: contain;
445
+    border-radius: 6px;
446
+}
447
+
448
+.avatar-uploader-icon {
449
+    font-size: 28px;
450
+    color: #8c939d;
451
+    width: 100px;
452
+    height: 100px;
453
+    line-height: 100px;
454
+    text-align: center;
455
+    border: 1px dashed #d9d9d9;
456
+    border-radius: 6px;
457
+    cursor: pointer;
458
+    transition: border-color 0.3s;
459
+}
460
+
461
+.avatar-uploader-icon:hover {
462
+    border-color: #409eff;
463
+}
464
+
465
+/* 图片上传组件样式优化 */
466
+:deep(.el-upload--picture-card) {
467
+    width: 100px;
468
+    height: 100px;
469
+    line-height: 100px;
470
+}
471
+
472
+:deep(.el-upload-list--picture-card .el-upload-list__item) {
473
+    width: 100px;
474
+    height: 100px;
475
+}
476
+
477
+:deep(.el-upload-list--picture-card .el-upload-list__item-thumbnail) {
478
+    width: 100%;
479
+    height: 100%;
480
+    object-fit: contain;
481
+}
482
+</style>

+ 335 - 253
src/views/system/role/index.vue

@@ -1,248 +1,195 @@
1 1
 <template>
2
-   <div class="app-container">
3
-      <el-form :model="queryParams" ref="queryRef" v-show="showSearch" :inline="true" label-width="68px">
4
-         <el-form-item label="角色名称" prop="roleName">
5
-            <el-input
6
-               v-model="queryParams.roleName"
7
-               placeholder="请输入角色名称"
8
-               clearable
9
-               style="width: 240px"
10
-               @keyup.enter="handleQuery"
11
-            />
12
-         </el-form-item>
13
-         <el-form-item label="权限字符" prop="roleKey">
14
-            <el-input
15
-               v-model="queryParams.roleKey"
16
-               placeholder="请输入权限字符"
17
-               clearable
18
-               style="width: 240px"
19
-               @keyup.enter="handleQuery"
20
-            />
21
-         </el-form-item>
22
-         <el-form-item label="状态" prop="status">
23
-            <el-select
24
-               v-model="queryParams.status"
25
-               placeholder="角色状态"
26
-               clearable
27
-               style="width: 240px"
28
-            >
29
-               <el-option
30
-                  v-for="dict in sys_normal_disable"
31
-                  :key="dict.value"
32
-                  :label="dict.label"
33
-                  :value="dict.value"
34
-               />
35
-            </el-select>
36
-         </el-form-item>
37
-         <el-form-item label="创建时间" style="width: 308px">
38
-            <el-date-picker
39
-               v-model="dateRange"
40
-               value-format="YYYY-MM-DD"
41
-               type="daterange"
42
-               range-separator="-"
43
-               start-placeholder="开始日期"
44
-               end-placeholder="结束日期"
45
-            ></el-date-picker>
46
-         </el-form-item>
47
-         <el-form-item>
48
-            <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
49
-            <el-button icon="Refresh" @click="resetQuery">重置</el-button>
50
-         </el-form-item>
51
-      </el-form>
52
-      <el-row :gutter="10" class="mb8">
53
-         <el-col :span="1.5">
54
-            <el-button
55
-               type="primary"
56
-               plain
57
-               icon="Plus"
58
-               @click="handleAdd"
59
-               v-hasPermi="['system:role:add']"
60
-            >新增</el-button>
61
-         </el-col>
62
-         <el-col :span="1.5">
63
-            <el-button
64
-               type="success"
65
-               plain
66
-               icon="Edit"
67
-               :disabled="single"
68
-               @click="handleUpdate"
69
-               v-hasPermi="['system:role:edit']"
70
-            >修改</el-button>
71
-         </el-col>
72
-         <el-col :span="1.5">
73
-            <el-button
74
-               type="danger"
75
-               plain
76
-               icon="Delete"
77
-               :disabled="multiple"
78
-               @click="handleDelete"
79
-               v-hasPermi="['system:role:remove']"
80
-            >删除</el-button>
81
-         </el-col>
82
-         <el-col :span="1.5">
83
-            <el-button
84
-               type="warning"
85
-               plain
86
-               icon="Download"
87
-               @click="handleExport"
88
-               v-hasPermi="['system:role:export']"
89
-            >导出</el-button>
90
-         </el-col>
91
-         <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
92
-      </el-row>
93
-
94
-      <!-- 表格数据 -->
95
-      <el-table v-loading="loading" :data="roleList" @selection-change="handleSelectionChange">
96
-         <el-table-column type="selection" width="55" align="center" />
97
-         <el-table-column label="角色编号" prop="roleId" width="120" />
98
-         <el-table-column label="角色名称" prop="roleName" :show-overflow-tooltip="true" width="150" />
99
-         <el-table-column label="权限字符" prop="roleKey" :show-overflow-tooltip="true" width="150" />
100
-         <el-table-column label="显示顺序" prop="roleSort" width="100" />
101
-         <el-table-column label="状态" align="center" width="100">
102
-            <template #default="scope">
103
-               <el-switch
104
-                  v-model="scope.row.status"
105
-                  active-value="0"
106
-                  inactive-value="1"
107
-                  @change="handleStatusChange(scope.row)"
108
-               ></el-switch>
109
-            </template>
110
-         </el-table-column>
111
-         <el-table-column label="创建时间" align="center" prop="createTime">
112
-            <template #default="scope">
113
-               <span>{{ parseTime(scope.row.createTime) }}</span>
114
-            </template>
115
-         </el-table-column>
116
-         <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
117
-            <template #default="scope">
118
-              <el-tooltip content="修改" placement="top" v-if="scope.row.roleId !== 1">
119
-                <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:role:edit']"></el-button>
120
-              </el-tooltip>
121
-              <el-tooltip content="删除" placement="top" v-if="scope.row.roleId !== 1">
122
-                <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:role:remove']"></el-button>
123
-              </el-tooltip>
124
-              <el-tooltip content="数据权限" placement="top" v-if="scope.row.roleId !== 1">
125
-                <el-button link type="primary" icon="CircleCheck" @click="handleDataScope(scope.row)" v-hasPermi="['system:role:edit']"></el-button>
2
+  <div class="app-container">
3
+    <el-form :model="queryParams" ref="queryRef" v-show="showSearch" :inline="true" label-width="68px">
4
+      <el-form-item label="角色名称" prop="roleName">
5
+        <el-input v-model="queryParams.roleName" placeholder="请输入角色名称" clearable style="width: 240px"
6
+          @keyup.enter="handleQuery" />
7
+      </el-form-item>
8
+      <el-form-item label="权限字符" prop="roleKey">
9
+        <el-input v-model="queryParams.roleKey" placeholder="请输入权限字符" clearable style="width: 240px"
10
+          @keyup.enter="handleQuery" />
11
+      </el-form-item>
12
+      <el-form-item label="状态" prop="status">
13
+        <el-select v-model="queryParams.status" placeholder="角色状态" clearable style="width: 240px">
14
+          <el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
15
+        </el-select>
16
+      </el-form-item>
17
+      <el-form-item label="创建时间" style="width: 308px">
18
+        <el-date-picker v-model="dateRange" value-format="YYYY-MM-DD" type="daterange" range-separator="-"
19
+          start-placeholder="开始日期" end-placeholder="结束日期"></el-date-picker>
20
+      </el-form-item>
21
+      <el-form-item>
22
+        <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
23
+        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
24
+      </el-form-item>
25
+    </el-form>
26
+    <el-row :gutter="10" class="mb8">
27
+      <el-col :span="1.5">
28
+        <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:role:add']">新增</el-button>
29
+      </el-col>
30
+      <el-col :span="1.5">
31
+        <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate"
32
+          v-hasPermi="['system:role:edit']">修改</el-button>
33
+      </el-col>
34
+      <el-col :span="1.5">
35
+        <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete"
36
+          v-hasPermi="['system:role:remove']">删除</el-button>
37
+      </el-col>
38
+      <el-col :span="1.5">
39
+        <el-button type="warning" plain icon="Download" @click="handleExport"
40
+          v-hasPermi="['system:role:export']">导出</el-button>
41
+      </el-col>
42
+      <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
43
+    </el-row>
44
+
45
+    <!-- 表格数据 -->
46
+    <el-table v-loading="loading" :data="roleList" @selection-change="handleSelectionChange">
47
+      <el-table-column type="selection" width="55" align="center" />
48
+      <el-table-column label="角色编号" prop="roleId" width="120" />
49
+      <el-table-column label="角色名称" prop="roleName" :show-overflow-tooltip="true" width="150" />
50
+      <el-table-column label="权限字符" prop="roleKey" :show-overflow-tooltip="true" width="150" />
51
+      <el-table-column label="显示顺序" prop="roleSort" width="100" />
52
+      <el-table-column label="状态" align="center" width="100">
53
+        <template #default="scope">
54
+          <el-switch v-model="scope.row.status" active-value="0" inactive-value="1"
55
+            @change="handleStatusChange(scope.row)"></el-switch>
56
+        </template>
57
+      </el-table-column>
58
+      <el-table-column label="创建时间" align="center" prop="createTime">
59
+        <template #default="scope">
60
+          <span>{{ parseTime(scope.row.createTime) }}</span>
61
+        </template>
62
+      </el-table-column>
63
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
64
+        <template #default="scope">
65
+          <el-tooltip content="修改" placement="top" v-if="scope.row.roleId !== 1">
66
+            <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)"
67
+              v-hasPermi="['system:role:edit']"></el-button>
68
+          </el-tooltip>
69
+          <el-tooltip content="删除" placement="top" v-if="scope.row.roleId !== 1">
70
+            <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)"
71
+              v-hasPermi="['system:role:remove']"></el-button>
72
+          </el-tooltip>
73
+          <el-tooltip content="数据权限" placement="top" v-if="scope.row.roleId !== 1">
74
+            <el-button link type="primary" icon="CircleCheck" @click="handleDataScope(scope.row)"
75
+              v-hasPermi="['system:role:edit']"></el-button>
76
+          </el-tooltip>
77
+          <el-tooltip content="分配用户" placement="top" v-if="scope.row.roleId !== 1">
78
+            <el-button link type="primary" icon="User" @click="handleAuthUser(scope.row)"
79
+              v-hasPermi="['system:role:edit']"></el-button>
80
+          </el-tooltip>
81
+        </template>
82
+      </el-table-column>
83
+    </el-table>
84
+
85
+    <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
86
+      v-model:limit="queryParams.pageSize" @pagination="getList" />
87
+
88
+    <!-- 添加或修改角色配置对话框 -->
89
+    <el-dialog :title="title" v-model="open" width="500px" append-to-body destroy-on-close>
90
+      <el-form ref="roleRef" :model="form" :rules="rules" label-width="100px">
91
+        <el-form-item label="角色名称" prop="roleName">
92
+          <el-input v-model="form.roleName" placeholder="请输入角色名称" />
93
+        </el-form-item>
94
+        <el-form-item prop="roleKey">
95
+          <template #label>
96
+            <span>
97
+              <el-tooltip content="控制器中定义的权限字符,如:@PreAuthorize(`@ss.hasRole('admin')`)" placement="top">
98
+                <el-icon><question-filled /></el-icon>
126 99
               </el-tooltip>
127
-              <el-tooltip content="分配用户" placement="top" v-if="scope.row.roleId !== 1">
128
-                <el-button link type="primary" icon="User" @click="handleAuthUser(scope.row)" v-hasPermi="['system:role:edit']"></el-button>
129
-              </el-tooltip>
130
-            </template>
131
-         </el-table-column>
132
-      </el-table>
133
-
134
-      <pagination
135
-         v-show="total > 0"
136
-         :total="total"
137
-         v-model:page="queryParams.pageNum"
138
-         v-model:limit="queryParams.pageSize"
139
-         @pagination="getList"
140
-      />
141
-
142
-      <!-- 添加或修改角色配置对话框 -->
143
-      <el-dialog :title="title" v-model="open" width="500px" append-to-body>
144
-         <el-form ref="roleRef" :model="form" :rules="rules" label-width="100px">
145
-            <el-form-item label="角色名称" prop="roleName">
146
-               <el-input v-model="form.roleName" placeholder="请输入角色名称" />
147
-            </el-form-item>
148
-            <el-form-item prop="roleKey">
149
-               <template #label>
150
-                  <span>
151
-                     <el-tooltip content="控制器中定义的权限字符,如:@PreAuthorize(`@ss.hasRole('admin')`)" placement="top">
152
-                        <el-icon><question-filled /></el-icon>
153
-                     </el-tooltip>
154
-                     权限字符
155
-                  </span>
156
-               </template>
157
-               <el-input v-model="form.roleKey" placeholder="请输入权限字符" />
158
-            </el-form-item>
159
-            <el-form-item label="角色顺序" prop="roleSort">
160
-               <el-input-number v-model="form.roleSort" controls-position="right" :min="0" />
161
-            </el-form-item>
162
-            <el-form-item label="状态">
163
-               <el-radio-group v-model="form.status">
164
-                  <el-radio
165
-                     v-for="dict in sys_normal_disable"
166
-                     :key="dict.value"
167
-                     :value="dict.value"
168
-                  >{{ dict.label }}</el-radio>
169
-               </el-radio-group>
170
-            </el-form-item>
171
-            <el-form-item label="菜单权限">
172
-               <el-checkbox v-model="menuExpand" @change="handleCheckedTreeExpand($event, 'menu')">展开/折叠</el-checkbox>
173
-               <el-checkbox v-model="menuNodeAll" @change="handleCheckedTreeNodeAll($event, 'menu')">全选/全不选</el-checkbox>
174
-               <el-checkbox v-model="form.menuCheckStrictly" @change="handleCheckedTreeConnect($event, 'menu')">父子联动</el-checkbox>
175
-               <el-tree
176
-                  class="tree-border"
177
-                  :data="menuOptions"
178
-                  show-checkbox
179
-                  ref="menuRef"
180
-                  node-key="id"
181
-                  :check-strictly="!form.menuCheckStrictly"
182
-                  empty-text="加载中,请稍候"
183
-                  :props="{ label: 'label', children: 'children' }"
184
-               ></el-tree>
185
-            </el-form-item>
186
-            <el-form-item label="备注">
187
-               <el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
188
-            </el-form-item>
189
-         </el-form>
190
-         <template #footer>
191
-            <div class="dialog-footer">
192
-               <el-button type="primary" @click="submitForm">确 定</el-button>
193
-               <el-button @click="cancel">取 消</el-button>
194
-            </div>
195
-         </template>
196
-      </el-dialog>
197
-
198
-      <!-- 分配角色数据权限对话框 -->
199
-      <el-dialog :title="title" v-model="openDataScope" width="500px" append-to-body>
200
-         <el-form :model="form" label-width="80px">
201
-            <el-form-item label="角色名称">
202
-               <el-input v-model="form.roleName" :disabled="true" />
203
-            </el-form-item>
204
-            <el-form-item label="权限字符">
205
-               <el-input v-model="form.roleKey" :disabled="true" />
206
-            </el-form-item>
207
-            <el-form-item label="权限范围">
208
-               <el-select v-model="form.dataScope" @change="dataScopeSelectChange">
209
-                  <el-option
210
-                     v-for="item in dataScopeOptions"
211
-                     :key="item.value"
212
-                     :label="item.label"
213
-                     :value="item.value"
214
-                  ></el-option>
215
-               </el-select>
216
-            </el-form-item>
217
-            <el-form-item label="数据权限" v-show="form.dataScope == 2">
218
-               <el-checkbox v-model="deptExpand" @change="handleCheckedTreeExpand($event, 'dept')">展开/折叠</el-checkbox>
219
-               <el-checkbox v-model="deptNodeAll" @change="handleCheckedTreeNodeAll($event, 'dept')">全选/全不选</el-checkbox>
220
-               <el-checkbox v-model="form.deptCheckStrictly" @change="handleCheckedTreeConnect($event, 'dept')">父子联动</el-checkbox>
221
-               <el-tree
222
-                  class="tree-border"
223
-                  :data="deptOptions"
224
-                  show-checkbox
225
-                  default-expand-all
226
-                  ref="deptRef"
227
-                  node-key="id"
228
-                  :check-strictly="!form.deptCheckStrictly"
229
-                  empty-text="加载中,请稍候"
230
-                  :props="{ label: 'label', children: 'children' }"
231
-               ></el-tree>
232
-            </el-form-item>
233
-         </el-form>
234
-         <template #footer>
235
-            <div class="dialog-footer">
236
-               <el-button type="primary" @click="submitDataScope">确 定</el-button>
237
-               <el-button @click="cancelDataScope">取 消</el-button>
238
-            </div>
239
-         </template>
240
-      </el-dialog>
241
-   </div>
100
+              权限字符
101
+            </span>
102
+          </template>
103
+          <el-input v-model="form.roleKey" placeholder="请输入权限字符" />
104
+        </el-form-item>
105
+        <el-form-item label="角色顺序" prop="roleSort">
106
+          <el-input-number v-model="form.roleSort" controls-position="right" :min="0" />
107
+        </el-form-item>
108
+        <el-form-item label="状态">
109
+          <el-radio-group v-model="form.status">
110
+            <el-radio v-for="dict in sys_normal_disable" :key="dict.value" :value="dict.value">{{ dict.label
111
+            }}</el-radio>
112
+          </el-radio-group>
113
+        </el-form-item>
114
+        <el-form-item label="菜单权限">
115
+          <el-checkbox v-model="menuExpand" @change="handleCheckedTreeExpand($event, 'menu')">展开/折叠</el-checkbox>
116
+          <el-checkbox v-model="menuNodeAll" @change="handleCheckedTreeNodeAll($event, 'menu')">全选/全不选</el-checkbox>
117
+          <el-checkbox v-model="form.menuCheckStrictly"
118
+            @change="handleCheckedTreeConnect($event, 'menu')">父子联动</el-checkbox>
119
+          <el-tree class="tree-border" :data="menuOptions" show-checkbox ref="menuRef" node-key="id"
120
+            :check-strictly="!form.menuCheckStrictly" empty-text="加载中,请稍候"
121
+            :props="{ label: 'label', children: 'children' }"></el-tree>
122
+        </el-form-item>
123
+        <el-form-item label="应用权限">
124
+          <view class="app-permission-container">
125
+            <view class="app-permission-header">
126
+              <view>应用名称</view>
127
+              <view>应用权限</view>
128
+              <view>首页展示</view>
129
+            </view>
130
+
131
+            <view v-for="(app, index) in appOptions" :key="app.appId" class="app-permission-row">
132
+              <div>{{ app.appName }}</div>
133
+
134
+              <el-checkbox :model-value="appIds.includes(app.appId)"
135
+                @change="handleAppPermissionChange($event, app.appId)">
136
+              </el-checkbox>
137
+
138
+              <el-checkbox :model-value="homePageAppIds.includes(app.appId)"
139
+                :disabled="homePageAppIds.length >= 4 && !homePageAppIds.includes(app.appId)"
140
+                @change="handleHomePageChange($event, app.appId)"></el-checkbox>
141
+            </view>
142
+          </view>
143
+        </el-form-item>
144
+        <el-form-item label="备注">
145
+          <el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
146
+        </el-form-item>
147
+      </el-form>
148
+      <template #footer>
149
+        <div class="dialog-footer">
150
+          <el-button type="primary" @click="submitForm">确 定</el-button>
151
+          <el-button @click="cancel">取 消</el-button>
152
+        </div>
153
+      </template>
154
+    </el-dialog>
155
+
156
+    <!-- 分配角色数据权限对话框 -->
157
+    <el-dialog :title="title" v-model="openDataScope" width="500px" append-to-body>
158
+      <el-form :model="form" label-width="80px">
159
+        <el-form-item label="角色名称">
160
+          <el-input v-model="form.roleName" :disabled="true" />
161
+        </el-form-item>
162
+        <el-form-item label="权限字符">
163
+          <el-input v-model="form.roleKey" :disabled="true" />
164
+        </el-form-item>
165
+        <el-form-item label="权限范围">
166
+          <el-select v-model="form.dataScope" @change="dataScopeSelectChange">
167
+            <el-option v-for="item in dataScopeOptions" :key="item.value" :label="item.label"
168
+              :value="item.value"></el-option>
169
+          </el-select>
170
+        </el-form-item>
171
+        <el-form-item label="数据权限" v-show="form.dataScope == 2">
172
+          <el-checkbox v-model="deptExpand" @change="handleCheckedTreeExpand($event, 'dept')">展开/折叠</el-checkbox>
173
+          <el-checkbox v-model="deptNodeAll" @change="handleCheckedTreeNodeAll($event, 'dept')">全选/全不选</el-checkbox>
174
+          <el-checkbox v-model="form.deptCheckStrictly"
175
+            @change="handleCheckedTreeConnect($event, 'dept')">父子联动</el-checkbox>
176
+          <el-tree class="tree-border" :data="deptOptions" show-checkbox default-expand-all ref="deptRef" node-key="id"
177
+            :check-strictly="!form.deptCheckStrictly" empty-text="加载中,请稍候"
178
+            :props="{ label: 'label', children: 'children' }"></el-tree>
179
+        </el-form-item>
180
+      </el-form>
181
+      <template #footer>
182
+        <div class="dialog-footer">
183
+          <el-button type="primary" @click="submitDataScope">确 定</el-button>
184
+          <el-button @click="cancelDataScope">取 消</el-button>
185
+        </div>
186
+      </template>
187
+    </el-dialog>
188
+  </div>
242 189
 </template>
243 190
 
244 191
 <script setup name="Role">
245
-import { addRole, changeRoleStatus, dataScope, delRole, getRole, listRole, updateRole, deptTreeSelect } from "@/api/system/role"
192
+import { addRole, changeRoleStatus, dataScope, delRole, getRole, listRole, updateRole, deptTreeSelect, listAllApp, listAppByRoleId } from "@/api/system/role"
246 193
 import { roleMenuTreeselect, treeselect as menuTreeselect } from "@/api/system/menu"
247 194
 
248 195
 const router = useRouter()
@@ -268,6 +215,12 @@ const deptOptions = ref([])
268 215
 const openDataScope = ref(false)
269 216
 const menuRef = ref(null)
270 217
 const deptRef = ref(null)
218
+const appOptions = ref([])
219
+const appNodeAll = ref(false)
220
+// 独立的应用权限数组
221
+const appIds = ref([])
222
+// 独立的首页应用数组
223
+const homePageAppIds = ref([])
271 224
 
272 225
 /** 数据范围选项*/
273 226
 const dataScopeOptions = ref([
@@ -296,6 +249,8 @@ const data = reactive({
296 249
 
297 250
 const { queryParams, form, rules } = toRefs(data)
298 251
 
252
+
253
+
299 254
 /** 查询角色列表 */
300 255
 function getList() {
301 256
   loading.value = true
@@ -327,7 +282,7 @@ function handleDelete(row) {
327 282
   }).then(() => {
328 283
     getList()
329 284
     proxy.$modal.msgSuccess("删除成功")
330
-  }).catch(() => {})
285
+  }).catch(() => { })
331 286
 }
332 287
 
333 288
 /** 导出按钮操作 */
@@ -382,6 +337,14 @@ function getMenuTreeselect() {
382 337
   })
383 338
 }
384 339
 
340
+/** 查询应用列表 */
341
+function getAppList() {
342
+  return listAllApp().then(response => {
343
+    appOptions.value = response.data || []
344
+    return response
345
+  })
346
+}
347
+
385 348
 /** 所有部门节点数据 */
386 349
 function getDeptAllCheckedKeys() {
387 350
   // 目前被选中的部门节点
@@ -401,6 +364,10 @@ function reset() {
401 364
   menuNodeAll.value = false
402 365
   deptExpand.value = true
403 366
   deptNodeAll.value = false
367
+  appNodeAll.value = false
368
+  // 重置独立的应用权限数组
369
+  appIds.value = []
370
+  homePageAppIds.value = []
404 371
   form.value = {
405 372
     roleId: undefined,
406 373
     roleName: undefined,
@@ -420,6 +387,7 @@ function reset() {
420 387
 function handleAdd() {
421 388
   reset()
422 389
   getMenuTreeselect()
390
+  getAppList()
423 391
   open.value = true
424 392
   title.value = "添加角色"
425 393
 }
@@ -430,15 +398,28 @@ function handleUpdate(row) {
430 398
   const roleId = row.roleId || ids.value
431 399
   const roleMenu = getRoleMenuTreeselect(roleId)
432 400
   getRole(roleId).then(response => {
433
-    form.value = response.data
401
+    form.value = {
402
+      ...response.data,
403
+    }
434 404
     form.value.roleSort = Number(form.value.roleSort)
435
-    open.value = true
436
-    nextTick(() => {
437
-      roleMenu.then((res) => {
438
-        let checkedKeys = res.checkedKeys
439
-        checkedKeys.forEach((v) => {
440
-          nextTick(() => {
441
-            menuRef.value.setChecked(v, true, false)
405
+
406
+    // 确保应用列表加载完成后再设置应用权限数据
407
+    Promise.all([getAppList(), listAppByRoleId(roleId)]).then(([appListRes, appRoleRes]) => {
408
+      // 使用独立的响应式变量
409
+      appIds.value = [...(appRoleRes.checkedAppIdList || [])]
410
+      homePageAppIds.value = [...(appRoleRes.checkedHomePageAppIdList || [])]
411
+      appNodeAll.value = appIds.value.length == appOptions.value.length
412
+
413
+      // 确保数据设置完成后再打开对话框
414
+      open.value = true
415
+
416
+      nextTick(() => {
417
+        roleMenu.then((res) => {
418
+          let checkedKeys = res.checkedKeys
419
+          checkedKeys.forEach((v) => {
420
+            nextTick(() => {
421
+              menuRef.value.setChecked(v, true, false)
422
+            })
442 423
           })
443 424
         })
444 425
       })
@@ -496,6 +477,62 @@ function handleCheckedTreeConnect(value, type) {
496 477
   }
497 478
 }
498 479
 
480
+/** 应用权限全选/全不选 */
481
+function handleCheckedAppAll(value) {
482
+  if (value) {
483
+    // 全选:获取所有应用的appId
484
+    appIds.value = appOptions.value.map(app => app.appId)
485
+  } else {
486
+    // 全不选:清空选中的应用
487
+    appIds.value = []
488
+  }
489
+}
490
+
491
+/** 应用权限选择变化处理 */
492
+function handleAppPermissionChange(checked, appId) {
493
+  if (checked) {
494
+    // 如果选中了应用权限,将应用ID添加到appIds数组中
495
+    if (!appIds.value.includes(appId)) {
496
+      // 使用响应式数组更新方式
497
+      appIds.value = [...appIds.value, appId]
498
+    }
499
+  } else {
500
+    // 如果取消选中应用权限,从appIds数组中移除应用ID
501
+    const index = appIds.value.indexOf(appId)
502
+    if (index > -1) {
503
+      // 使用响应式数组更新方式
504
+      appIds.value = appIds.value.filter(id => id !== appId)
505
+    }
506
+    // 同时从homePageAppIds数组中移除该应用ID(如果存在)
507
+    const homePageIndex = homePageAppIds.value.indexOf(appId)
508
+    if (homePageIndex > -1) {
509
+      homePageAppIds.value = homePageAppIds.value.filter(id => id !== appId)
510
+    }
511
+  }
512
+}
513
+
514
+/** 首页应用选择变化处理 */
515
+function handleHomePageChange(checked, appId) {
516
+  if (checked) {
517
+    // 如果选择了首页应用,确保对应的应用权限也被选中
518
+    if (!appIds.value.includes(appId)) {
519
+      // 使用响应式数组更新方式
520
+      appIds.value = [...appIds.value, appId]
521
+    }
522
+    // 将应用ID添加到homePageAppIds数组中
523
+    if (!homePageAppIds.value.includes(appId)) {
524
+      homePageAppIds.value = [...homePageAppIds.value, appId]
525
+    }
526
+  } else {
527
+    // 如果取消选中首页应用,从homePageAppIds数组中移除应用ID
528
+    const index = homePageAppIds.value.indexOf(appId)
529
+    if (index > -1) {
530
+      // 使用响应式数组更新方式
531
+      homePageAppIds.value = homePageAppIds.value.filter(id => id !== appId)
532
+    }
533
+  }
534
+}
535
+
499 536
 /** 所有菜单节点数据 */
500 537
 function getMenuAllCheckedKeys() {
501 538
   // 目前被选中的菜单节点
@@ -510,16 +547,23 @@ function getMenuAllCheckedKeys() {
510 547
 function submitForm() {
511 548
   proxy.$refs["roleRef"].validate(valid => {
512 549
     if (valid) {
550
+      // 将独立的应用权限数据合并到form对象中
551
+      const submitData = {
552
+        ...form.value,
553
+        appIds: appIds.value,
554
+        homePageAppIds: homePageAppIds.value
555
+      }
556
+
513 557
       if (form.value.roleId != undefined) {
514
-        form.value.menuIds = getMenuAllCheckedKeys()
515
-        updateRole(form.value).then(response => {
558
+        submitData.menuIds = getMenuAllCheckedKeys()
559
+        updateRole(submitData).then(response => {
516 560
           proxy.$modal.msgSuccess("修改成功")
517 561
           open.value = false
518 562
           getList()
519 563
         })
520 564
       } else {
521
-        form.value.menuIds = getMenuAllCheckedKeys()
522
-        addRole(form.value).then(response => {
565
+        submitData.menuIds = getMenuAllCheckedKeys()
566
+        addRole(submitData).then(response => {
523 567
           proxy.$modal.msgSuccess("新增成功")
524 568
           open.value = false
525 569
           getList()
@@ -582,3 +626,41 @@ function cancelDataScope() {
582 626
 
583 627
 getList()
584 628
 </script>
629
+
630
+<style scoped>
631
+.app-permission-container {
632
+  display: flex;
633
+  flex-direction: column;
634
+  width: 100%;
635
+  border: 1px solid var(--el-border-color);
636
+  border-radius: 4px;
637
+  padding: 5px;
638
+}
639
+
640
+.app-permission-header {
641
+  display: grid;
642
+  grid-template-columns: 1.6fr 1fr 1fr;
643
+  font-weight: bold;
644
+  align-items: center;
645
+
646
+  height: 24px;
647
+  line-height: 24px;
648
+  padding: 0 8px;
649
+}
650
+
651
+.app-permission-row {
652
+  height: 24px;
653
+  line-height: 24px;
654
+  display: grid;
655
+  grid-template-columns: 2fr 1fr 1fr;
656
+  align-items: center;
657
+  gap: 16px;
658
+  padding: 0 8px;
659
+}
660
+
661
+.app-permission-row div:first-child {
662
+  min-height: 32px;
663
+  display: flex;
664
+  align-items: center;
665
+}
666
+</style>

+ 256 - 32
src/views/system/user/components/UserInfoEdit.vue

@@ -26,12 +26,12 @@
26 26
             </el-form-item>
27 27
           </el-col>
28 28
           <el-col :span="12">
29
-            <el-form-item v-if=" form.userId == undefined " label="用户名称" prop="userName">
29
+            <el-form-item v-if="form.userId == undefined" label="用户名称" prop="userName">
30 30
               <el-input v-model="form.userName" placeholder="请输入用户名称" maxlength="30" />
31 31
             </el-form-item>
32 32
           </el-col>
33 33
           <el-col :span="12">
34
-            <el-form-item v-if=" form.userId == undefined " label="用户密码" prop="password">
34
+            <el-form-item v-if="form.userId == undefined" label="用户密码" prop="password">
35 35
               <el-input v-model="form.password" placeholder="请输入用户密码" type="password" maxlength="20" show-password />
36 36
             </el-form-item>
37 37
           </el-col>
@@ -43,24 +43,39 @@
43 43
           <el-col :span="12">
44 44
             <el-form-item label="用户性别" prop="sex">
45 45
               <el-select v-model="form.sex" placeholder="请选择用户性别">
46
-                <el-option v-for=" dict in sys_user_sex " :key="dict.value" :label="dict.label"
46
+                <el-option v-for="dict in sys_user_sex" :key="dict.value" :label="dict.label"
47 47
                   :value="dict.value"></el-option>
48 48
               </el-select>
49 49
             </el-form-item>
50 50
           </el-col>
51 51
           <el-col :span="12">
52
-            <el-form-item label="政治面貌" prop="politicalStatus">
53
-              <el-select v-model="form.politicalStatus" placeholder="请选择政治面貌">
54
-                <el-option v-for=" item in sys_user_political_status " :key="item.value" :label="item.label"
52
+            <el-form-item label="生肖" prop="zodiac">
53
+              <el-select v-model="form.zodiac" placeholder="请选择生肖">
54
+                <el-option v-for="item in sys_user_zodiac" :key="item.value" :label="item.label" :value="item.value" />
55
+              </el-select>
56
+            </el-form-item>
57
+          </el-col>
58
+          <el-col :span="12">
59
+            <el-form-item label="星座" prop="constellation">
60
+              <el-select v-model="form.constellation" placeholder="请选择星座">
61
+                <el-option v-for="item in sys_user_constellation" :key="item.value" :label="item.label"
62
+                  :value="item.value" />
63
+              </el-select>
64
+            </el-form-item>
65
+          </el-col>
66
+          <el-col :span="12">
67
+            <el-form-item label="血型" prop="blooGroup">
68
+              <el-select v-model="form.blooGroup" placeholder="请选择血型">
69
+                <el-option v-for="item in sys_user_blood_group" :key="item.value" :label="item.label"
55 70
                   :value="item.value" />
56 71
               </el-select>
57 72
             </el-form-item>
58 73
           </el-col>
74
+
59 75
           <el-col :span="12">
60 76
             <el-form-item label="角色" prop="roleIds">
61 77
               <el-select v-model="form.roleIds" multiple placeholder="请选择角色" @change="roleChange">
62
-                <el-option v-for=" item in roleOptions " :key="item.roleId" :label="item.roleName"
63
-                  :value="item.roleId"
78
+                <el-option v-for="item in roleOptions" :key="item.roleId" :label="item.roleName" :value="item.roleId"
64 79
                   :disabled="item.status == 1"></el-option>
65 80
               </el-select>
66 81
             </el-form-item>
@@ -72,7 +87,7 @@
72 87
           <el-col :span="12">
73 88
             <el-form-item label="账号状态" prop="status">
74 89
               <el-radio-group v-model="form.status">
75
-                <el-radio v-for=" dict in sys_normal_disable " :key="dict.value" :value="dict.value">
90
+                <el-radio v-for="dict in sys_normal_disable" :key="dict.value" :value="dict.value">
76 91
                   {{ dict.label }}
77 92
                 </el-radio>
78 93
               </el-radio-group>
@@ -81,7 +96,7 @@
81 96
           <el-col :span="12">
82 97
             <el-form-item label="培训合规状态" prop="trainingComplianceStatus">
83 98
               <el-radio-group v-model="form.trainingComplianceStatus">
84
-                <el-radio v-for=" dict in sys_user_training_compliance_status " :key="dict.value" :value="dict.value">
99
+                <el-radio v-for="dict in sys_user_training_compliance_status" :key="dict.value" :value="dict.value">
85 100
                   {{ dict.label }}
86 101
                 </el-radio>
87 102
               </el-radio-group>
@@ -89,28 +104,48 @@
89 104
           </el-col>
90 105
         </el-row>
91 106
       </el-card>
92
-      <el-card header="资质与岗位信息" style="margin-bottom: 10px;">
107
+      <el-card header="资质能力" style="margin-bottom: 10px;">
93 108
         <el-row :gutter="16">
94 109
           <el-col :span="12">
95 110
             <el-form-item label="资质等级" prop="qualificationLevel"
96
-              :rules="( form.roleIds || [] ).includes( 101 ) || ( form.roleIds || [] ).includes( 102 ) ? [ { required: true, message: '请选择资质等级', trigger: 'blur' } ] : []">
111
+              :rules="(form.roleIds || []).includes(101) || (form.roleIds || []).includes(102) ? [{ required: true, message: '请选择资质等级', trigger: 'blur' }] : []">
97 112
               <el-select v-model="form.qualificationLevel" placeholder="请选择资质等级">
98
-                <el-option v-for=" item in sys_user_qualification_level " :key="item.value" :label="item.label"
113
+                <el-option v-for="item in sys_user_qualification_level" :key="item.value" :label="item.label"
99 114
                   :value="item.value" />
100 115
               </el-select>
101 116
             </el-form-item>
102 117
           </el-col>
103 118
           <el-col :span="12">
104 119
             <el-form-item label="岗位类型" prop="postIds"
105
-              :rules="( form.roleIds || [] ).includes( 101 ) || ( form.roleIds || [] ).includes( 102 ) ? [ { required: true, message: '请选择岗位类型', trigger: 'blur' } ] : []">
120
+              :rules="(form.roleIds || []).includes(101) || (form.roleIds || []).includes(102) ? [{ required: true, message: '请选择岗位类型', trigger: 'blur' }] : []">
106 121
               <el-cascader v-model="form.postIds" :options="treeData" :props="treeNodeProps" filterable
107 122
                 style="width: 100%" />
108 123
             </el-form-item>
109 124
           </el-col>
110
-        </el-row>
111
-      </el-card>
112
-      <el-card header="人员异常状态记录" style="margin-bottom: 10px;">
113
-        <el-row :gutter="16">
125
+          <el-col :span="12">
126
+            <el-form-item label="是否通过政审" prop="politicalReviewSituation">
127
+              <el-radio-group v-model="form.politicalReviewSituation">
128
+                <el-radio :value="'1'">是</el-radio>
129
+                <el-radio :value="'0'">否</el-radio>
130
+              </el-radio-group>
131
+            </el-form-item>
132
+          </el-col>
133
+          <el-col :span="12">
134
+            <el-form-item label="政治面貌" prop="politicalStatus">
135
+              <el-select v-model="form.politicalStatus" placeholder="请选择政治面貌">
136
+                <el-option v-for="item in sys_user_political_status" :key="item.value" :label="item.label"
137
+                  :value="item.value" />
138
+              </el-select>
139
+            </el-form-item>
140
+          </el-col>
141
+          <el-col :span="12">
142
+            <el-form-item label="学历" prop="schooling">
143
+              <el-select v-model="form.schooling" placeholder="请选择学历">
144
+                <el-option v-for="item in sys_user_schooling" :key="item.value" :label="item.label"
145
+                  :value="item.value" />
146
+              </el-select>
147
+            </el-form-item>
148
+          </el-col>
114 149
           <el-col :span="24">
115 150
             <el-form-item label="行政处罚情况" prop="administrativeStatus">
116 151
               <el-input v-model="form.administrativeStatus" type="textarea" placeholder="请输入行政处罚情况"></el-input>
@@ -123,6 +158,184 @@
123 158
           </el-col>
124 159
         </el-row>
125 160
       </el-card>
161
+      <el-card header="工作履历/经验" style="margin-bottom: 10px;">
162
+        <el-row :gutter="16">
163
+          <el-col :span="12">
164
+            <el-form-item label="开始工作时间" prop="startWorkingDate">
165
+              <el-date-picker v-model="form.startWorkingDate" type="date" placeholder="请选择开始工作时间" value-format="YYYY-MM-DD" style="width: 100%;" />
166
+            </el-form-item>
167
+          </el-col>
168
+          <el-col :span="12">
169
+            <el-form-item label="开始安检工作时间" prop="securityCheckStartDate" label-width="140px">
170
+              <el-date-picker v-model="form.securityCheckStartDate" type="date" placeholder="请选择开始安检工作时间" value-format="YYYY-MM-DD" style="width: 100%;" />
171
+            </el-form-item>
172
+          </el-col>
173
+          <el-col :span="12">
174
+            <el-form-item label="曾在安检工作中担任的最高职务" prop="securityInspectionPosition" label-width="220px">
175
+              <el-select v-model="form.securityInspectionPosition" placeholder="请选择曾在安检工作中担任的最高职务">
176
+                <el-option label="安检员" value="安检员" />
177
+                <el-option label="班组长" value="班组长" />
178
+              </el-select>
179
+            </el-form-item>
180
+          </el-col>
181
+          <el-col :span="12">
182
+            <el-form-item label="接受奖励次数" prop="workRewardsNumber">
183
+              <el-input v-model="form.workRewardsNumber" type="number" placeholder="请输入接受奖励次数" min="0" />
184
+            </el-form-item>
185
+          </el-col>
186
+          <el-col :span="12">
187
+            <el-form-item label="接受处罚次数" prop="workPenaltiesNumber">
188
+              <el-input v-model="form.workPenaltiesNumber" type="number" placeholder="请输入接受处罚次数" min="0" />
189
+            </el-form-item>
190
+          </el-col>
191
+        </el-row>
192
+      </el-card>
193
+      <el-card header="评价类指标" style="margin-bottom: 10px;">
194
+        <el-row :gutter="16">
195
+          <el-col :span="12">
196
+            <el-form-item label="性格特征" prop="characterCharacteristics">
197
+              <el-select v-model="form.characterCharacteristics" placeholder="请选择性格特征">
198
+                <el-option v-for="item in sys_user_character_characteristics" :key="item.value" :label="item.label"
199
+                  :value="item.value" />
200
+              </el-select>
201
+            </el-form-item>
202
+          </el-col>
203
+          <el-col :span="12">
204
+            <el-form-item label="工作风格" prop="workingStyle">
205
+              <el-select v-model="form.workingStyle" placeholder="请选择工作风格">
206
+                <el-option v-for="item in sys_user_working_style" :key="item.value" :label="item.label"
207
+                  :value="item.value" />
208
+              </el-select>
209
+            </el-form-item>
210
+          </el-col>
211
+          <el-col :span="12">
212
+            <el-form-item label="团队配合人员" prop="teamCooperation">
213
+              <UserSelect v-model="form.teamCooperation" :multiple="true" :max="3" :placeholder="'请选择团队配合人员(最多3人)'"
214
+                width="100%" />
215
+            </el-form-item>
216
+          </el-col>
217
+          <el-col :span="24">
218
+            <el-form-item label="自我关键词评价" prop="selfKeywords">
219
+              <el-row :gutter="8" style="width: 100%;">
220
+                <el-col :span="6">
221
+                  <el-select v-model="form.selfAssessmentPersonalityTrait" placeholder="请选择性格特质">
222
+                    <el-option v-for="item in sys_user_personality_trait" :key="item.value" :label="item.label"
223
+                      :value="item.value" />
224
+                  </el-select>
225
+                </el-col>
226
+                <el-col :span="6">
227
+                  <el-select v-model="form.selfAssessmentCapabilityPerformance" placeholder="请选择能力表现">
228
+                    <el-option v-for="item in sys_user_capability_performance" :key="item.value" :label="item.label"
229
+                      :value="item.value" />
230
+                  </el-select>
231
+                </el-col>
232
+                <el-col :span="6">
233
+                  <el-select v-model="form.selfAssessmentInterpersonalInteraction" placeholder="请选择人际互动">
234
+                    <el-option v-for="item in sys_user_interpersonal_interaction" :key="item.value" :label="item.label"
235
+                      :value="item.value" />
236
+                  </el-select>
237
+                </el-col>
238
+                <el-col :span="6">
239
+                  <el-select v-model="form.selfAssessmentGrowthPotential" placeholder="请选择成长潜力">
240
+                    <el-option v-for="item in sys_user_growth_potential" :key="item.value" :label="item.label"
241
+                      :value="item.value" />
242
+                  </el-select>
243
+                </el-col>
244
+              </el-row>
245
+            </el-form-item>
246
+          </el-col>
247
+          <el-col :span="24">
248
+            <el-form-item label="同事关键词评价" prop="colleagueKeywords">
249
+              <el-row :gutter="8" style="width: 100%;">
250
+                <el-col :span="6">
251
+                  <el-select v-model="form.colleagueCommentsPersonalityTrait" placeholder="请选择性格特质">
252
+                    <el-option v-for="item in sys_user_personality_trait" :key="item.value" :label="item.label"
253
+                      :value="item.value" />
254
+                  </el-select>
255
+                </el-col>
256
+                <el-col :span="6">
257
+                  <el-select v-model="form.colleagueCommentsCapabilityPerformance" placeholder="请选择能力表现">
258
+                    <el-option v-for="item in sys_user_capability_performance" :key="item.value" :label="item.label"
259
+                      :value="item.value" />
260
+                  </el-select>
261
+                </el-col>
262
+                <el-col :span="6">
263
+                  <el-select v-model="form.colleagueCommentsInterpersonalInteraction" placeholder="请选择人际互动">
264
+                    <el-option v-for="item in sys_user_interpersonal_interaction" :key="item.value" :label="item.label"
265
+                      :value="item.value" />
266
+                  </el-select>
267
+                </el-col>
268
+                <el-col :span="6">
269
+                  <el-select v-model="form.colleagueCommentsGrowthPotential" placeholder="请选择成长潜力">
270
+                    <el-option v-for="item in sys_user_growth_potential" :key="item.value" :label="item.label"
271
+                      :value="item.value" />
272
+                  </el-select>
273
+                </el-col>
274
+              </el-row>
275
+            </el-form-item>
276
+          </el-col>
277
+          <el-col :span="24">
278
+            <el-form-item label="上级关键词评价" prop="superiorKeywords">
279
+              <el-row :gutter="8" style="width: 100%;">
280
+                <el-col :span="6">
281
+                  <el-select v-model="form.superiorEvaluationPersonalityTrait" placeholder="请选择性格特质">
282
+                    <el-option v-for="item in sys_user_personality_trait" :key="item.value" :label="item.label"
283
+                      :value="item.value" />
284
+                  </el-select>
285
+                </el-col>
286
+                <el-col :span="6">
287
+                  <el-select v-model="form.superiorEvaluationCapabilityPerformance" placeholder="请选择能力表现">
288
+                    <el-option v-for="item in sys_user_capability_performance" :key="item.value" :label="item.label"
289
+                      :value="item.value" />
290
+                  </el-select>
291
+                </el-col>
292
+                <el-col :span="6">
293
+                  <el-select v-model="form.superiorEvaluationInterpersonalInteraction" placeholder="请选择人际互动">
294
+                    <el-option v-for="item in sys_user_interpersonal_interaction" :key="item.value" :label="item.label"
295
+                      :value="item.value" />
296
+                  </el-select>
297
+                </el-col>
298
+                <el-col :span="6">
299
+                  <el-select v-model="form.superiorEvaluationGrowthPotential" placeholder="请选择成长潜力">
300
+                    <el-option v-for="item in sys_user_growth_potential" :key="item.value" :label="item.label"
301
+                      :value="item.value" />
302
+                  </el-select>
303
+                </el-col>
304
+              </el-row>
305
+            </el-form-item>
306
+          </el-col>
307
+          <el-col :span="24">
308
+            <el-form-item label="下级关键词评价" prop="subordinateKeywords">
309
+              <el-row :gutter="8" style="width: 100%;">
310
+                <el-col :span="6">
311
+                  <el-select v-model="form.subordinateEvaluationPersonalityTrait" placeholder="请选择性格特质">
312
+                    <el-option v-for="item in sys_user_personality_trait" :key="item.value" :label="item.label"
313
+                      :value="item.value" />
314
+                  </el-select>
315
+                </el-col>
316
+                <el-col :span="6">
317
+                  <el-select v-model="form.subordinateEvaluationCapabilityPerformance" placeholder="请选择能力表现">
318
+                    <el-option v-for="item in sys_user_capability_performance" :key="item.value" :label="item.label"
319
+                      :value="item.value" />
320
+                  </el-select>
321
+                </el-col>
322
+                <el-col :span="6">
323
+                  <el-select v-model="form.subordinateEvaluationInterpersonalInteraction" placeholder="请选择人际互动">
324
+                    <el-option v-for="item in sys_user_interpersonal_interaction" :key="item.value" :label="item.label"
325
+                      :value="item.value" />
326
+                  </el-select>
327
+                </el-col>
328
+                <el-col :span="6">
329
+                  <el-select v-model="form.subordinateEvaluationGrowthPotential" placeholder="请选择成长潜力">
330
+                    <el-option v-for="item in sys_user_growth_potential" :key="item.value" :label="item.label"
331
+                      :value="item.value" />
332
+                  </el-select>
333
+                </el-col>
334
+              </el-row>
335
+            </el-form-item>
336
+          </el-col>
337
+        </el-row>
338
+      </el-card>
126 339
       <el-card header="应急联络信息" style="margin-bottom: 10px;">
127 340
         <el-row :gutter="16">
128 341
           <el-col :span="12">
@@ -139,8 +352,7 @@
139 352
           <el-col :span="12">
140 353
             <el-form-item label="紧急联系人关系" prop="emergencyContactRelationship">
141 354
               <el-select v-model="form.emergencyContactRelationship" placeholder="请选择联系人关系">
142
-                <el-option v-for=" item in sys_user_emergency_contact_relationship " :key="item.value"
143
-                  :label="item.label"
355
+                <el-option v-for="item in sys_user_emergency_contact_relationship" :key="item.value" :label="item.label"
144 356
                   :value="item.value" />
145 357
               </el-select>
146 358
             </el-form-item>
@@ -164,6 +376,7 @@
164 376
 import { onMounted, reactive, computed } from 'vue';
165 377
 import { useDict } from '@/utils/dict'
166 378
 import { listAllTree } from '@/api/system/post'
379
+import UserSelect from '@/components/UserSelect/index.vue'
167 380
 // 重父页面迁移过来的代码 2处公用选择框数据 选择使用父组件传入
168 381
 defineProps({
169 382
   sys_user_sex: {
@@ -189,24 +402,35 @@ defineProps({
189 402
 })
190 403
 const userRef = ref(null)
191 404
 const form = defineModel('form', ref({}))
192
-// 政治面貌、资质等级、紧急联系人关系
405
+
406
+// 政治面貌、资质等级、紧急联系人关系、生肖、星座、血型、是否通过政审、学历、性格特征、工作风格、团队配合、关键词、能力表现、人际互动、成长潜力
193 407
 const {
194 408
   sys_user_political_status,
195 409
   sys_user_qualification_level,
196 410
   sys_user_emergency_contact_relationship,
197
-  sys_user_training_compliance_status
198
-} = useDict('sys_user_political_status', 'sys_user_qualification_level', 'sys_user_emergency_contact_relationship', 'sys_user_training_compliance_status')
411
+  sys_user_training_compliance_status,
412
+  sys_user_zodiac,
413
+  sys_user_constellation,
414
+  sys_user_blood_group,
415
+  sys_user_personality_trait,
416
+  sys_user_schooling,
417
+  sys_user_character_characteristics,
418
+  sys_user_working_style,
419
+  sys_user_capability_performance,
420
+  sys_user_interpersonal_interaction,
421
+  sys_user_growth_potential
422
+} = useDict('sys_user_personality_trait', 'sys_user_political_status', 'sys_user_qualification_level', 'sys_user_emergency_contact_relationship', 'sys_user_training_compliance_status', 'sys_user_zodiac', 'sys_user_constellation', 'sys_user_blood_group', 'sys_user_schooling', 'sys_user_character_characteristics', 'sys_user_working_style', 'sys_user_capability_performance', 'sys_user_interpersonal_interaction', 'sys_user_growth_potential')
199 423
 
200 424
 const rules = computed(() => ({
201
-  userName: [ { required: true, message: "用户名称不能为空", trigger: "blur" }, { min: 2, max: 20, message: "用户名称长度必须介于 2 和 20 之间", trigger: "blur" } ],
202
-  deptId: [ { required: true, message: '请选择归属部门', trigger: "blur" } ],
203
-  nickName: [ { required: true, message: "用户昵称不能为空", trigger: "blur" } ],
204
-  password: [ { required: true, message: "用户密码不能为空", trigger: "blur" }, { min: 5, max: 20, message: "用户密码长度必须介于 5 和 20 之间", trigger: "blur" }, { pattern: /^[^<>"'|\\]+$/, message: "不能包含非法字符:< > \" ' \\\ |", trigger: "blur" } ],
205
-  email: [ { type: "email", message: "请输入正确的邮箱地址", trigger: [ "blur", "change" ] } ],
206
-  phonenumber: [ { pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: "请输入正确的手机号码", trigger: "blur" } ],
207
-  emergencyContactPhone: [ { pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: "请输入正确的手机号码", trigger: "blur" } ],
208
-  roleIds: [ { required: true, message: '请选择角色', trigger: "blur" } ],
209
-  status: [ { required: true, message: '请选择账号状态', trigger: "blur" } ]
425
+  userName: [{ required: true, message: "用户名称不能为空", trigger: "blur" }, { min: 2, max: 20, message: "用户名称长度必须介于 2 和 20 之间", trigger: "blur" }],
426
+  deptId: [{ required: true, message: '请选择归属部门', trigger: "blur" }],
427
+  nickName: [{ required: true, message: "用户昵称不能为空", trigger: "blur" }],
428
+  password: [{ required: true, message: "用户密码不能为空", trigger: "blur" }, { min: 5, max: 20, message: "用户密码长度必须介于 5 和 20 之间", trigger: "blur" }, { pattern: /^[^<>"'|\\]+$/, message: "不能包含非法字符:< > \" ' \\\ |", trigger: "blur" }],
429
+  email: [{ type: "email", message: "请输入正确的邮箱地址", trigger: ["blur", "change"] }],
430
+  phonenumber: [{ pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: "请输入正确的手机号码", trigger: "blur" }],
431
+  emergencyContactPhone: [{ pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: "请输入正确的手机号码", trigger: "blur" }],
432
+  roleIds: [{ required: true, message: '请选择角色', trigger: "blur" }],
433
+  status: [{ required: true, message: '请选择账号状态', trigger: "blur" }]
210 434
 }))
211 435
 
212 436
 const treeNodeProps = { multiple: true, expandTrigger: 'hover', label: 'postName', value: 'postId', emitPath: false, checkOnClickNode: true }

+ 47 - 6
src/views/system/user/index.vue

@@ -123,7 +123,7 @@
123 123
     </el-row>
124 124
 
125 125
     <!-- 添加或修改用户配置对话框 -->
126
-    <el-dialog :title="title" v-model="open" width="75vw" hei append-to-body>
126
+    <el-dialog :title="title" v-model="open" width="75vw" hei append-to-body destroy-on-close>
127 127
       <UserInfoEdit ref="userRef" v-model:form="form" :sys_user_sex="sys_user_sex"
128 128
         :enabledDeptOptions="enabledDeptOptions"
129 129
         :sys_normal_disable="sys_normal_disable" :postOptions="postOptions" :roleOptions="roleOptions" />
@@ -166,7 +166,7 @@
166 166
 <script setup name="User">
167 167
 import { getToken } from "@/utils/auth"
168 168
 import useAppStore from '@/store/modules/app'
169
-import { changeUserStatus, listUser, resetUserPwd, delUser, getUser, updateUser, addUser, deptTreeSelect } from "@/api/system/user"
169
+import { changeUserStatus, listUser, resetUserPwd, delUser, getUser, updateUser, addUser, deptTreeSelect,listAllUser} from "@/api/system/user"
170 170
 import { Splitpanes, Pane } from "splitpanes"
171 171
 import "splitpanes/dist/splitpanes.css"
172 172
 import UserInfoEdit from './components/UserInfoEdit.vue'
@@ -192,6 +192,7 @@ const enabledDeptOptions = ref(undefined)
192 192
 const initPassword = ref(undefined)
193 193
 const postOptions = ref([])
194 194
 const roleOptions = ref([])
195
+const allUserList = ref([])
195 196
 /*** 用户导入参数 */
196 197
 const upload = reactive({
197 198
   // 是否显示弹出层(用户导入)
@@ -238,6 +239,15 @@ const filterNode = (value, data) => {
238 239
   return data.label.indexOf(value) !== -1
239 240
 }
240 241
 
242
+/** 查询所有用户 */
243
+const getAllUserList = () => {
244
+  listAllUser().then(res => {
245
+    
246
+    allUserList.value = res.data
247
+  })
248
+}
249
+// getAllUserList()
250
+
241 251
 /** 根据名称筛选部门树 */
242 252
 watch(deptName, val => {
243 253
   proxy.$refs[ "deptTreeRef" ].filter(val)
@@ -251,6 +261,7 @@ function getList () {
251 261
     userList.value = res.rows
252 262
     total.value = res.total
253 263
   })
264
+
254 265
 }
255 266
 
256 267
 /** 查询部门下拉树结构 */
@@ -417,7 +428,8 @@ function reset () {
417 428
     status: "0",
418 429
     remark: undefined,
419 430
     postIds: [],
420
-    roleIds: []
431
+    roleIds: [],
432
+    teamCooperation:[]
421 433
   }
422 434
   proxy.$refs[ "userRef" ] && proxy.$refs[ "userRef" ].resetForm()
423 435
 }
@@ -448,7 +460,11 @@ function handleUpdate (row) {
448 460
   open.value = true
449 461
   getUser(userId).then(response => {
450 462
     reset()
451
-    form.value = response.data
463
+    form.value = {
464
+      ...response.data,
465
+      teamCooperation:response.data.teamCooperation?response.data.teamCooperation.split(",").map(Number) : []
466
+    }
467
+    
452 468
     postOptions.value = response.posts
453 469
     roleOptions.value = response.roles
454 470
     form.value.postIds = response.postIds || []
@@ -461,14 +477,39 @@ function handleUpdate (row) {
461 477
 /** 提交按钮 */
462 478
 function submitForm () {
463 479
   proxy.$refs[ "userRef" ].submit().then(() => {
480
+    // console.log(form.value,"form.value")
481
+    // debugger
482
+    // // 获取teamCooperationUsers选中的人员对象
483
+    // const teamCooperationUserIds = form.value.teamCooperation || []
484
+    // const teamCooperationUsers = []
485
+    
486
+    // if (teamCooperationUserIds.length > 0) {
487
+    //   // 从用户列表中查找对应的用户对象
488
+    //   teamCooperationUserIds.forEach(userId => {
489
+    //     const user = allUserList.value.find(u => u.userId === userId)
490
+    //     if (user) {
491
+    //       teamCooperationUsers.push({
492
+    //         ...user
493
+    //       })
494
+    //     }
495
+    //   })
496
+    
497
+    // }
498
+    
499
+    // 将teamCooperationUsers对象添加到表单数据中
500
+    const submitData = {
501
+      ...form.value,
502
+      teamCooperation: form.value.teamCooperation.join(",")
503
+    }
504
+
464 505
     if (form.value.userId != undefined) {
465
-      updateUser(form.value).then(response => {
506
+      updateUser(submitData).then(response => {
466 507
         proxy.$modal.msgSuccess("修改成功")
467 508
         open.value = false
468 509
         getList()
469 510
       })
470 511
     } else {
471
-      addUser(form.value).then(response => {
512
+      addUser(submitData).then(response => {
472 513
         proxy.$modal.msgSuccess("新增成功")
473 514
         open.value = false
474 515
         getList()

+ 346 - 0
src/views/system/workingDocument/index.vue

@@ -0,0 +1,346 @@
1
+<template>
2
+  <div class="app-container">
3
+    <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
4
+      <el-form-item label="文档标题" prop="documentTitle">
5
+        <el-input v-model="queryParams.documentTitle" placeholder="请输入文档标题" clearable @keyup.enter="handleQuery" />
6
+      </el-form-item>
7
+
8
+      <el-form-item label="创建者" prop="createBy">
9
+        <el-input v-model="queryParams.createBy" placeholder="请输入创建者" clearable @keyup.enter="handleQuery" />
10
+      </el-form-item>
11
+
12
+      <el-form-item label="状态" prop="status">
13
+        <el-select v-model="queryParams.status" placeholder="请选择状态" clearable style="width: 200px;">
14
+          <el-option label="正常" :value="1" />
15
+          <el-option label="关闭" :value="0" />
16
+        </el-select>
17
+      </el-form-item>
18
+
19
+      <el-form-item>
20
+        <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
21
+        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
22
+      </el-form-item>
23
+    </el-form>
24
+
25
+    <el-row :gutter="10" class="mb8">
26
+      <el-col :span="1.5">
27
+        <el-button type="primary" plain icon="Plus" @click="handleAdd"
28
+          v-hasPermi="['system:workingDocument:add']">新增</el-button>
29
+      </el-col>
30
+      <!-- <el-col :span="1.5">
31
+        <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate"
32
+          v-hasPermi="['system:workDocu:edit']">修改</el-button>
33
+      </el-col> -->
34
+      <el-col :span="1.5">
35
+        <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete"
36
+          v-hasPermi="['system:workingDocument:remove']">删除</el-button>
37
+      </el-col>
38
+      <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
39
+    </el-row>
40
+
41
+    <el-table v-loading="loading" :data="docList" @selection-change="handleSelectionChange" :row-key="getRowKey">
42
+      <el-table-column type="selection" width="55" align="center" />
43
+      <el-table-column type="index" label="序号" align="center" width="80" />
44
+      <el-table-column label="文档标题" align="center" prop="documentTitle" />
45
+      <el-table-column label="状态" align="center" prop="status">
46
+        <template #default="scope">
47
+          <dict-tag :options="sys_normal_disable" :value="scope.row.status" />
48
+        </template>
49
+      </el-table-column>
50
+      <el-table-column label="创建者" align="center" prop="createBy" />
51
+      <el-table-column label="创建时间" align="center" prop="createTime" width="180">
52
+        <template #default="scope">
53
+          <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
54
+        </template>
55
+      </el-table-column>
56
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
57
+        <template #default="scope">
58
+          <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)"
59
+            v-hasPermi="['system:workingDocument:edit']">修改</el-button>
60
+          <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)"
61
+            v-hasPermi="['system:workingDocument:remove']">删除</el-button>
62
+        </template>
63
+      </el-table-column>
64
+    </el-table>
65
+
66
+    <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
67
+      v-model:limit="queryParams.pageSize" @pagination="getList" />
68
+
69
+    <!-- 添加或修改工作文档对话框 -->
70
+    <el-dialog :title="title" v-model="open" width="600" append-to-body destroy-on-close>
71
+      <el-form ref="docRef" :model="form" :rules="rules" label-width="9em">
72
+        <el-form-item label="文档标题" prop="documentTitle">
73
+          <el-input v-model="form.documentTitle" placeholder="请输入文档标题" maxlength="49" />
74
+        </el-form-item>
75
+        <el-form-item label="状态" prop="status">
76
+          <el-radio-group v-model="form.status">
77
+            <el-radio :label="'1'">正常</el-radio>
78
+            <el-radio :label="'0'">关闭</el-radio>
79
+          </el-radio-group>
80
+        </el-form-item>
81
+        <el-form-item label="文档文件" prop="documentUrl">
82
+          <el-upload ref="uploadRef" :limit="1" accept=".pdf" :headers="upload.headers" :action="upload.url"
83
+            :file-list="upload.fileList" :disabled="false" :on-success="handleFileSuccess" :on-remove="handleFileRemove"
84
+            :auto-upload="true" drag style="width:300px">
85
+            <el-icon class="el-icon--upload"><upload-filled /></el-icon>
86
+            <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
87
+            <template #tip>
88
+              <div class="el-upload__tip text-center">
89
+                <span>仅允许导入pdf格式文件,且文件大小不超过10MB。</span>
90
+              </div>
91
+            </template>
92
+          </el-upload>
93
+        </el-form-item>
94
+      </el-form>
95
+      <template #footer>
96
+        <div class="dialog-footer">
97
+          <el-button @click="cancel">取 消</el-button>
98
+          <el-button type="primary" @click="submitForm">确 定</el-button>
99
+        </div>
100
+      </template>
101
+    </el-dialog>
102
+  </div>
103
+</template>
104
+
105
+<script setup name="WorkDocu">
106
+import { onMounted, ref, reactive, toRefs, computed } from 'vue'
107
+import { ElMessage } from 'element-plus'
108
+import { UploadFilled } from '@element-plus/icons-vue'
109
+import Pagination from '@/components/Pagination/index.vue'
110
+import RightToolbar from '@/components/RightToolbar/index.vue'
111
+import { parseTime } from '@/utils/ruoyi'
112
+import { getToken } from '@/utils/auth'
113
+import { listWorkDocu, getWorkDocu, deleteWorkDocu, addWorkDocu, updateWorkDocu } from '@/api/system/workDocu'
114
+const { proxy } = getCurrentInstance()
115
+
116
+// 使用真实API接口,已从@/api/system/workDocu导入
117
+const sys_normal_disable = [
118
+  { label: '正常', value: '1' },
119
+  { label: '关闭', value: '0', elTagType: 'danger' }
120
+]
121
+
122
+const getRowKey = (row) => {
123
+  return row.documentId
124
+}
125
+
126
+// 表格数据
127
+const docList = ref([])
128
+const open = ref(false)
129
+const loading = ref(true)
130
+const showSearch = ref(true)
131
+const ids = ref([])
132
+const single = ref(true)
133
+const multiple = ref(true)
134
+const total = ref(0)
135
+const title = ref('')
136
+
137
+// 上传相关
138
+const uploadRef = ref(null)
139
+
140
+const upload = reactive({
141
+  fileList: [],
142
+  // 是否显示弹出层
143
+  open: false,
144
+  // 弹出层标题
145
+  title: "",
146
+  // 是否禁用上传
147
+  isUploading: false,
148
+  // 是否更新已经存在的用户数据
149
+  updateSupport: 0,
150
+  // 设置上传的请求头部
151
+  headers: { Authorization: "Bearer " + getToken() },
152
+  // 上传的地址
153
+  url: import.meta.env.VITE_APP_BASE_API + "/common/upload"
154
+})
155
+
156
+// 文件上传成功处理
157
+const handleFileSuccess = (response, file, fileList) => {
158
+
159
+  if (response.code === 200) {
160
+    
161
+    form.value.documentFileName =  response.fileName;
162
+    form.value.documentNewFileName = response.newFileName;
163
+    form.value.documentOriginalFileName = response.originalFilename;
164
+    form.value.documentUrl = response.url
165
+    ElMessage.success('上传成功')
166
+  } else {
167
+    ElMessage.error(response.msg || '上传失败')
168
+  }
169
+}
170
+
171
+// 文件移除处理
172
+const handleFileRemove = (file, fileList) => {
173
+  // form.value.documentTitle = '';
174
+  form.value.documentFileName = '';
175
+  form.value.documentUrl = '';
176
+}
177
+
178
+// 表单数据
179
+const data = reactive({
180
+  form: {
181
+    id: null,
182
+    documentTitle: '',
183
+    status: '1',
184
+    documentUrl: ''
185
+  },
186
+  queryParams: {
187
+    pageNum: 1,
188
+    pageSize: 10,
189
+    documentTitle: '',
190
+    createBy: '',
191
+    status: null
192
+  },
193
+  rules: {
194
+    documentTitle: [
195
+      { required: true, message: '文档标题不能为空', trigger: 'blur' }
196
+    ],
197
+    documentUrl: [
198
+      { required: true, message: '文档文件不能为空', trigger: 'blur' }
199
+    ]
200
+  }
201
+})
202
+
203
+const { queryParams, form, rules } = toRefs(data)
204
+
205
+/** 查询文档列表 */
206
+const getList = () => {
207
+  loading.value = true
208
+  listWorkDocu(queryParams.value).then(response => {
209
+    docList.value = response.rows
210
+    total.value = response.total
211
+    loading.value = false
212
+  })
213
+}
214
+
215
+// 取消按钮
216
+const cancel = () => {
217
+  open.value = false
218
+  reset()
219
+}
220
+
221
+// 表单重置
222
+const reset = () => {
223
+  form.value = {
224
+    id: null,
225
+    documentTitle: '',
226
+    status: '1',
227
+    documentUrl: ''
228
+  }
229
+  // 清空文件列表
230
+  upload.fileList = []
231
+  if (proxy?.$refs?.docRef) {
232
+    proxy.$refs.docRef.resetFields()
233
+  }
234
+}
235
+
236
+/** 搜索按钮操作 */
237
+const handleQuery = () => {
238
+  queryParams.value.pageNum = 1
239
+  getList()
240
+}
241
+
242
+/** 重置按钮操作 */
243
+const resetQuery = () => {
244
+  if (proxy?.$refs?.queryRef) {
245
+    proxy.$refs.queryRef.resetFields()
246
+  }
247
+  handleQuery()
248
+}
249
+
250
+// 多选框选中数据
251
+const handleSelectionChange = (selection) => {
252
+  ids.value = selection.map(item => item.documentId)
253
+  single.value = selection.length !== 1
254
+  multiple.value = !selection.length
255
+}
256
+
257
+/** 新增按钮操作 */
258
+const handleAdd = () => {
259
+  reset()
260
+  open.value = true
261
+  title.value = '添加工作文档'
262
+}
263
+
264
+/** 修改按钮操作 */
265
+const handleUpdate = (row) => {
266
+  reset()
267
+
268
+  const _id = row?.documentId || ids.value
269
+  getWorkDocu(_id).then(response => {
270
+    form.value = response.data;
271
+    upload.fileList = [{
272
+      name: response.data.documentOriginalFileName,
273
+      url: response.data.documentUrl
274
+    }]
275
+    open.value = true
276
+    title.value = '修改工作文档'
277
+  })
278
+}
279
+
280
+/** 提交按钮 */
281
+const submitForm = () => {
282
+  if (proxy?.$refs?.docRef) {
283
+    proxy.$refs.docRef.validate((valid) => {
284
+      if (valid) {
285
+        if (form.value.documentId != null) {
286
+
287
+          updateWorkDocu(form.value).then(response => {
288
+            ElMessage.success('修改成功')
289
+            open.value = false
290
+            getList()
291
+          })
292
+        } else {
293
+          addWorkDocu(form.value).then(response => {
294
+            ElMessage.success('新增成功')
295
+            open.value = false
296
+            getList()
297
+          })
298
+        }
299
+      }
300
+    })
301
+  }
302
+}
303
+
304
+/** 删除按钮操作 */
305
+const handleDelete = (row) => {
306
+  const _ids = row?.documentId || ids.value;
307
+
308
+  if (proxy?.$modal) {
309
+    proxy.$modal.confirm('是否确认删除数据项?').then(() => {
310
+      // 如果是数组就join,如果不是就直接传
311
+      const deleteIds = Array.isArray(_ids) ? _ids.join(',') : _ids;
312
+      return deleteWorkDocu(deleteIds)
313
+    }).then(() => {
314
+      getList()
315
+      ElMessage.success('删除成功')
316
+    }).catch(() => { })
317
+  }
318
+}
319
+
320
+// 页面加载时获取数据
321
+onMounted(() => {
322
+  getList()
323
+})
324
+</script>
325
+
326
+<style scoped>
327
+.app-container {
328
+  padding: 20px;
329
+}
330
+
331
+.mb8 {
332
+  margin-bottom: 8px;
333
+}
334
+
335
+.fixed-width {
336
+  width: 140px;
337
+}
338
+
339
+.small-padding .cell {
340
+  padding: 10px 5px;
341
+}
342
+
343
+.dialog-footer {
344
+  text-align: right;
345
+}
346
+</style>

+ 12 - 0
vite/plugins/auto-import.js

@@ -0,0 +1,12 @@
1
+import autoImport from 'unplugin-auto-import/vite'
2
+
3
+export default function createAutoImport() {
4
+    return autoImport({
5
+        imports: [
6
+            'vue',
7
+            'vue-router',
8
+            'pinia'
9
+        ],
10
+        dts: false
11
+    })
12
+}

+ 28 - 0
vite/plugins/compression.js

@@ -0,0 +1,28 @@
1
+import compression from 'vite-plugin-compression'
2
+
3
+export default function createCompression(env) {
4
+    const { VITE_BUILD_COMPRESS } = env
5
+    const plugin = []
6
+    if (VITE_BUILD_COMPRESS) {
7
+        const compressList = VITE_BUILD_COMPRESS.split(',')
8
+        if (compressList.includes('gzip')) {
9
+            // http://doc.ruoyi.vip/ruoyi-vue/other/faq.html#使用gzip解压缩静态文件
10
+            plugin.push(
11
+                compression({
12
+                    ext: '.gz',
13
+                    deleteOriginFile: false
14
+                })
15
+            )
16
+        }
17
+        if (compressList.includes('brotli')) {
18
+            plugin.push(
19
+                compression({
20
+                    ext: '.br',
21
+                    algorithm: 'brotliCompress',
22
+                    deleteOriginFile: false
23
+                })
24
+            )
25
+        }
26
+    }
27
+    return plugin
28
+}

+ 15 - 0
vite/plugins/index.js

@@ -0,0 +1,15 @@
1
+import vue from '@vitejs/plugin-vue'
2
+
3
+import createAutoImport from './auto-import'
4
+import createSvgIcon from './svg-icon'
5
+import createCompression from './compression'
6
+import createSetupExtend from './setup-extend'
7
+
8
+export default function createVitePlugins(viteEnv, isBuild = false) {
9
+    const vitePlugins = [vue()]
10
+    vitePlugins.push(createAutoImport())
11
+	vitePlugins.push(createSetupExtend())
12
+    vitePlugins.push(createSvgIcon(isBuild))
13
+	isBuild && vitePlugins.push(...createCompression(viteEnv))
14
+    return vitePlugins
15
+}

+ 5 - 0
vite/plugins/setup-extend.js

@@ -0,0 +1,5 @@
1
+import setupExtend from 'unplugin-vue-setup-extend-plus/vite'
2
+
3
+export default function createSetupExtend() {
4
+    return setupExtend({})
5
+}

+ 10 - 0
vite/plugins/svg-icon.js

@@ -0,0 +1,10 @@
1
+import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
2
+import path from 'path'
3
+
4
+export default function createSvgIcon(isBuild) {
5
+    return createSvgIconsPlugin({
6
+		iconDirs: [path.resolve(process.cwd(), 'src/assets/icons/svg')],
7
+        symbolId: 'icon-[dir]-[name]',
8
+        svgoOptions: isBuild
9
+    })
10
+}