Forráskód Böngészése

修改管理及菜单部分

yangg 5 napja
szülő
commit
86b23de73b

+ 9 - 0
src/router/route.ts

@@ -45,6 +45,15 @@ export const dynamicRoutes: Array<RouteRecordRaw> = [
 			isIframe: false,
 			icon: 'iconfont icon-gerenzhongxin',
 		},
+	},
+	{
+		path: '/system/contract/preview',
+		name: 'contractPreview',
+		component: () => import('/@/views/system/contract/preview.vue'),
+		meta: {
+			title: '合约预览',
+			isHide: true,
+		},
 	}
 ];
 

+ 1 - 0
src/stores/interface/index.ts

@@ -18,6 +18,7 @@ export interface UserInfosState {
 		dept_name: string;
 	};
 	role_info: any[];
+	tenant_id:string;
 }
 export interface UserInfosStates {
 	userInfos: UserInfosState;

+ 4 - 0
src/stores/userInfo.ts

@@ -29,6 +29,7 @@ export const useUserInfo = defineStore('userInfo', {
 					name: '',
 				},
 			],
+			tenant_id:''
 		},
 		isSocketOpen: false
 	}),
@@ -46,6 +47,7 @@ export const useUserInfo = defineStore('userInfo', {
 			this.userInfos.dept_info = userInfos.dept_info;
 			this.userInfos.role_info = userInfos.role_info;
 			this.userInfos.pwd_change_count = userInfos.pwd_change_count;
+			this.userInfos.tenant_id=userInfos.data.tenant_id
 			Session.set('userInfo', this.userInfos);
 		},
 		async setUserInfos() {
@@ -63,6 +65,7 @@ export const useUserInfo = defineStore('userInfo', {
 				this.userInfos.dept_info = userInfos.data.dept_info;
 				this.userInfos.role_info = userInfos.data.role_info;
 				this.userInfos.pwd_change_count = userInfos.data.pwd_change_count;
+				this.userInfos.tenant_id=userInfos.data.tenant_id
 				Session.set('userInfo', this.userInfos);
 			}
 		},
@@ -83,6 +86,7 @@ export const useUserInfo = defineStore('userInfo', {
 				this.userInfos.dept_info = res.data.dept_info;
 				this.userInfos.role_info = res.data.role_info;
 				this.userInfos.pwd_change_count = res.data.pwd_change_count;
+				this.userInfos.tenant_id=res.data.tenant_id
 				Session.set('userInfo', this.userInfos);
 			})
 		},

+ 1 - 1
src/views/JobApplication/list/crud.tsx

@@ -343,7 +343,7 @@ export const createCrudOptions = function ({ crudExpose, context}: CreateCrudOpt
 						text: '重新分析',
 						iconRight: 'Refresh',
 						type: 'text',
-						show:true /* compute(({ row }) => {
+						show:false /* compute(({ row }) => {
 							return row.status === 2; // 只在状态为"已面试"时显示
 						}) */,
 						order: 2,

+ 2 - 2
src/views/system/company/crud.tsx

@@ -89,10 +89,10 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp
 						iconRight: '',
 						type: 'text',
 						show: true,//auth('company:ViewContract'),
-						/* click: ({ row }) => {
+						click: ({ row }) => {
 							// TODO: 实现查看合约逻辑,例如导航到合约页面
 							console.log('查看合约 for company:', row);
-						} */
+						}
 					},
 					edit: {
 						show: false,

+ 54 - 3
src/views/system/contract/crud.tsx

@@ -4,8 +4,10 @@ import { dict, UserPageQuery, AddReq, DelReq, EditReq, compute, CreateCrudOption
 import { dictionary } from '/@/utils/dictionary';
 import { successMessage } from '/@/utils/message';
 import { auth } from '/@/utils/authFunction';
+import { useRouter } from 'vue-router';
 
 export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProps): CreateCrudOptionsRet {
+	const router = useRouter();
 	const pageRequest = async (query: UserPageQuery) => {
 		return await api.GetList(query);
 	};
@@ -20,6 +22,16 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp
 		return await api.AddObj(form);
 	};
 
+	const handleViewContract = (row: any) => {
+		router.push({
+			path: '/system/contract/preview',
+			query: {
+				file: row.contract_file,
+				contractName: row.contract_name
+			}
+		});
+	};
+
 	return {
 		crudOptions: {
 			toolbar:{
@@ -71,9 +83,18 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp
 				fixed: 'right',
 				width: 200,
 				buttons: {
-					view: { iconRight: 'View', type: 'text', show: true },
-					edit: { iconRight: 'Edit', type: 'text', show: true },
-					remove: { iconRight: 'Delete', type: 'text', show: true },
+					view: { text: '详细信息', iconRight: 'View', type: 'text', show: true },
+					edit: { iconRight: 'Edit', type: 'text', show: false },
+					remove: { iconRight: 'Delete', type: 'text', show: false },
+					Viewcontract: {
+						text:'查看合约',
+						iconRight:'',
+						type:'text',
+						show:true,
+						click: (opts: any) => {
+							handleViewContract(opts.row);
+						}
+					},
 				},
 			},
 			columns: {
@@ -92,6 +113,36 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp
 					},
 					column: { minWidth: 150 },
 				},
+				contract_file: {
+					title: '合约文档',
+					type: 'file-uploader',
+					form: {
+						/* rules: [{ required: true, message: '请上传合约文档' }], */
+						component: {
+							uploader: {
+								type: 'form',
+								action: '/api/platform/upload/',
+								accept: '.pdf,.doc,.docx',
+								maxSize: 10 * 1024 * 1024, // 10MB
+								limit: 1,
+							},
+							placeholder: '请上传PDF或Word格式的合约文档',
+							helpMessage: '支持PDF、Word格式,文件大小不超过10MB'
+						}
+					},
+					column: {
+						show:false,
+						component: {
+							// 自定义显示
+							render: ({ value }) => {
+								if (!value) return '未上传';
+								const fileName = value.split('/').pop();
+								return <el-link type="primary" href={value} target="_blank">{fileName}</el-link>;
+							}
+						},
+						minWidth: 180
+					}
+				},
 				contract_name: {
 					title: '合约名称',
 					search: { show: true },

+ 70 - 2
src/views/system/contract/index.vue

@@ -1,18 +1,86 @@
 <template>
 	<fs-page>
-		<fs-crud ref="crudRef" v-bind="crudBinding"> </fs-crud>
+		<fs-crud ref="crudRef" v-bind="crudBinding">
+			<template #form_contract_file="{ value, onChange, formData }">
+				<div>
+					<el-upload
+						v-model:file-list="fileList"
+						class="upload-demo"
+						:action="uploadUrl"
+						:headers="{
+								'Authorization': `JWT ${Session.get('token') || ''}`
+							}"
+						:on-change="handleChange"
+						:before-upload="beforeUpload"
+						:on-success="handleSuccess"
+						:on-error="handleError"
+						:limit="1"
+					>
+						<el-button type="primary">点击上传</el-button>
+						<template #tip>
+							<div class="el-upload__tip">
+								请上传合同文件,支持 PDF/DOC/DOCX 格式
+							</div>
+						</template>
+					</el-upload>
+				</div>
+			</template>
+		</fs-crud>
 	</fs-page>
 </template>
 
 <script lang="ts" setup name="contract">
-import { onMounted } from 'vue';
+import { onMounted, ref } from 'vue';
 import { useFs } from '@fast-crud/fast-crud';
 import { createCrudOptions } from './crud';
 import { GetPermission } from './api';
 import { handleColumnPermission } from '/@/utils/columnPermission';
+import type { UploadFile, UploadFiles } from 'element-plus';
+import { ElMessage } from 'element-plus';
+import { Session } from '/@/utils/storage';
 
 const { crudBinding, crudRef, crudExpose, crudOptions, resetCrudOptions } = useFs({ createCrudOptions });
 
+// 文件列表
+const fileList = ref<UploadFiles>([]);
+
+// 上传地址
+const uploadUrl = ref(import.meta.env.VITE_API_URL + '/api/system/admin_upload/');
+
+// 上传前验证
+const beforeUpload = (file: File) => {
+  const validTypes = ['application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'];
+  const isValidType = validTypes.includes(file.type);
+  const isLt10M = file.size / 1024 / 1024 < 10;
+
+  if (!isValidType) {
+    ElMessage.error('只能上传PDF/DOC/DOCX文件!');
+    return false;
+  }
+  if (!isLt10M) {
+    ElMessage.error('文件大小不能超过 10MB!');
+    return false;
+  }
+  return true;
+};
+
+// 文件状态改变时的钩子
+const handleChange = (uploadFile: UploadFile, uploadFiles: UploadFiles) => {
+  console.log('文件变化:', uploadFile, uploadFiles);
+};
+
+// 上传成功回调
+const handleSuccess = (response: any, uploadFile: UploadFile, uploadFiles: UploadFiles) => {
+  ElMessage.success('上传成功');
+  console.log('上传成功:', response);
+};
+
+// 上传失败回调
+const handleError = (error: Error, uploadFile: UploadFile, uploadFiles: UploadFiles) => {
+  ElMessage.error('上传失败');
+  console.error('上传失败:', error);
+};
+
 // 页面打开后获取列表数据
 onMounted(async () => {
 	// 设置列权限

+ 116 - 0
src/views/system/contract/preview.vue

@@ -0,0 +1,116 @@
+<template>
+  <div class="contract-preview">
+    <div class="preview-header">
+     <!--  <el-page-header @back="goBack" :title="route.query.contractName">
+        <template #content>
+          <span class="preview-title">合约预览</span>
+        </template>
+      </el-page-header> -->
+    </div>
+    
+    <div class="preview-content">
+      <!-- PDF预览 -->
+      <template v-if="fileType === 'pdf'">
+        <iframe :src="previewUrl" class="pdf-viewer"></iframe>
+      </template>
+      
+      <!-- Word文档预览 -->
+      <template v-else-if="fileType === 'word'">
+        <div class="word-preview">
+          <el-empty v-if="!officePreviewUrl" description="正在加载文档预览...">
+            <el-button type="primary" @click="downloadFile">下载文档</el-button>
+          </el-empty>
+          <iframe v-else :src="officePreviewUrl" class="word-viewer"></iframe>
+        </div>
+      </template>
+      
+      <!-- 不支持的文件类型 -->
+      <template v-else>
+        <el-empty description="不支持的文件类型">
+          <el-button type="primary" @click="downloadFile">下载文档</el-button>
+        </el-empty>
+      </template>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, computed, onMounted } from 'vue';
+import { useRoute, useRouter } from 'vue-router';
+
+const route = useRoute();
+const router = useRouter();
+
+const fileUrl = computed(() => route.query.file as string);
+const fileType = computed(() => {
+  const ext = fileUrl.value?.toLowerCase().split('.').pop();
+  if (ext === 'pdf') return 'pdf';
+  if (['doc', 'docx'].includes(ext || '')) return 'word';
+  return 'unknown';
+});
+
+// 处理PDF预览URL
+const previewUrl = computed(() => {
+  if (fileType.value === 'pdf') {
+    return fileUrl.value;
+  }
+  return '';
+});
+
+// 处理Word文档预览URL(使用Microsoft Office Online Viewer)
+const officePreviewUrl = computed(() => {
+  if (fileType.value === 'word') {
+    // 使用微软在线预览服务
+    return `https://view.officeapps.live.com/op/embed.aspx?src=${encodeURIComponent(fileUrl.value)}`;
+  }
+  return '';
+});
+
+const goBack = () => {
+  router.back();
+};
+
+const downloadFile = () => {
+  window.open(fileUrl.value, '_blank');
+};
+</script>
+
+<style scoped>
+.contract-preview {
+  padding: 20px;
+  height: 100vh;
+  display: flex;
+  flex-direction: column;
+}
+
+.preview-header {
+  margin-bottom: 20px;
+}
+
+.preview-title {
+  font-size: 18px;
+  font-weight: bold;
+}
+
+.preview-content {
+  flex: 1;
+  background: #fff;
+  border-radius: 4px;
+  box-shadow: 0 2px 12px 0 rgba(0,0,0,0.1);
+  overflow: hidden;
+}
+
+.pdf-viewer,
+.word-viewer {
+  width: 100%;
+  height: 100%;
+  border: none;
+}
+
+.word-preview {
+  height: 100%;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+</style> 

+ 8 - 4
src/views/system/role/crud.tsx

@@ -3,6 +3,7 @@ import * as api from './api';
 import { dictionary } from '/@/utils/dictionary';
 import { successMessage } from '../../../utils/message';
 import { auth } from '/@/utils/authFunction';
+import { Session } from '/@/utils/storage';
 
 /**
  *
@@ -39,7 +40,7 @@ export const createCrudOptions = function ({ crudExpose, context }: CreateCrudOp
 			actionbar: {
 				buttons: {
 					add: {
-						show: auth('role:Create'),
+						show: true,//auth('role:Create'),
 					},
 				},
 			},
@@ -52,15 +53,18 @@ export const createCrudOptions = function ({ crudExpose, context }: CreateCrudOp
 						show: true,
 					},
 					edit: {
-						show: auth('role:Update'),
+						show: true,//auth('role:Update'),
 					},
 					remove: {
-						show: auth('role:Delete'),
+						show: true,//auth('role:Delete'),
 					},
 					permission: {
 						type: 'primary',
 						text: '权限配置',
-						show: false,//auth('role:Permission'),
+						show: compute(({ row }) => {
+							/* console.log(Session.get('userInfo')); */
+							return Session.get('userInfo').role_info[0]?.id === 1; // 只在状态为"已面试"时显示
+						}),//true,auth('role:Permission'),
 						click: (clickContext: any): void => {
 							const { row } = clickContext;
 							context.RoleDrawer.handleDrawerOpen(row);

+ 2 - 1
src/views/system/user/api.ts

@@ -1,5 +1,6 @@
 import { request,downloadFile } from '/@/utils/service';
 import { PageQuery, AddReq, DelReq, EditReq, InfoReq } from '@fast-crud/fast-crud';
+import { Session } from '/@/utils/storage';
 
 export const apiPrefix = '/api/system/user/';
 
@@ -15,7 +16,7 @@ export function GetList(query: PageQuery) {
     return request({
         url: apiPrefix,
         method: 'get',
-        params: query,
+        params: {...query,tenant_id:1},
     });
 }
 export function GetObj(id: InfoReq) {

+ 5 - 5
src/views/system/user/crud.tsx

@@ -74,12 +74,12 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp
             actionbar: {
                 buttons: {
                     add: {
-                        show: auth('user:Create')
+                        show: true,//auth('user:Create')
                     },
                     export: {
                         text: "导出",//按钮文字
                         title: "导出",//鼠标停留显示的信息
-                        show: auth('user:Export'),
+                        show: true,//auth('user:Export'),
                         click: (ctx: any) => ElMessageBox.confirm(
                             '确定重设密码吗?', '提示',
                             { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }
@@ -98,17 +98,17 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp
                     edit: {
                         iconRight: 'Edit',
                         type: 'text',
-                        show: auth('user:Update'),
+                        show: true,//auth('user:Update'),
                     },
                     remove: {
                         iconRight: 'Delete',
                         type: 'text',
-                        show: auth('user:Delete'),
+                        show: true,//auth('user:Delete'),
                     },
                     custom: {
                         text: '重设密码',
                         type: 'text',
-                        show: auth('user:ResetPassword'),
+                        show:true,// auth('user:ResetPassword'),
                         tooltip: {
                             placement: 'top',
                             content: '重设密码',