yangg 2 mēneši atpakaļ
vecāks
revīzija
ab6fb0f802

+ 1 - 1
.env.development

@@ -6,7 +6,7 @@ ENV = 'development'
 # 本地环境接口地址 121.36.251.245
 
 
-VITE_API_URL = 'https://backend.qicai321.com'
+VITE_API_URL = 'http://192.168.100.115:8083'
 # VITE_API_URL = 'https://backend.qicai321.com'
 VITE_API_WX_URL='https://api.weixin.qq.com/'
 VITE_API_URL_MINLONG='http://117.185.80.170:7861'

+ 14 - 9
src/components/avatarSelector/index.vue

@@ -22,7 +22,7 @@
 			</el-row>
 			<br />
 			<el-row class="flex justify-center">
-				<el-col :lg="2" :md="2">
+				<el-col :lg="2" :md="2" :sm="2">
 					<el-upload action="#" :http-request="requestUpload" :show-file-list="false" :before-upload="beforeUpload">
 						<el-button type="success">
 							选择
@@ -123,15 +123,20 @@ function beforeUpload(file) {
 	if (!isImageFile(file.name)) {
 		ElMessage.error('文件格式错误,请上传图片类型,如:JPG,PNG等后缀的文件。');
 		return false;
-	} else {
-		const reader = new FileReader();
-		reader.readAsDataURL(file);
-		reader.onload = () => {
-			options.img = reader.result;
-			options.fileName = file.name;
-		};
-		return true;
 	}
+	// 检查文件大小是否超过20MB
+	const maxSize = 20 * 1024 * 1024; // 20MB转换为字节
+	if (file.size > maxSize) {
+		ElMessage.error('文件大小不能超过20MB');
+		return false;
+	}
+	const reader = new FileReader();
+	reader.readAsDataURL(file);
+	reader.onload = () => {
+		options.img = reader.result;
+		options.fileName = file.name;
+	};
+	return true;
 }
 /** 上传图片 */
 function uploadImg() {

+ 23 - 4
src/views/JobApplication/list/components/smSnotification.vue

@@ -30,7 +30,7 @@
         <!-- 消息内容 -->
         <div class="message-content">
           <!-- 根据当前模板显示内容 -->
-          <div v-if="currentTemplate" v-html="currentTemplate.template"></div>
+          <div v-if="currentTemplate" v-html="processedTemplate"></div>
           <!-- 当没有模板时显示的默认内容 -->
           <div v-else class="no-template">
             暂无可用的短信模板
@@ -54,7 +54,7 @@
           </div>
         </div>
         <div class="notification-right-content">
-          <div v-if="currentTemplate" v-html="currentTemplate.template"></div>
+          <div v-if="currentTemplate" v-html="processedTemplate"></div>
         </div>
       </div>
     </div>
@@ -154,9 +154,15 @@ const editFormRef = ref<FormInstance>();
 // 添加当前状态的响应式变量
 const currentStatus = ref(0);
 
+interface Template {
+  id: number;
+  template: string;
+  type: number;
+}
+
 // 添加模板相关的响应式变量
-const templates = ref([]);
-const currentTemplate = ref(null);
+const templates = ref<Template[]>([]);
+const currentTemplate = ref<Template | null>(null);
 
 // 原有表单数据
 const form = reactive({
@@ -518,6 +524,19 @@ const getTemplateTypeName = computed(() => {
       return '通用模板';
   }
 });
+
+// 处理模板变量替换
+const processedTemplate = computed(() => {
+  if (!currentTemplate.value) return '';
+  
+  let template = currentTemplate.value.template;
+  
+  // 替换模板中的变量
+  template = template.replace(/\${name}/g, editForm.candidateName || '');
+  template = template.replace(/\${job}/g, editForm.position || '');
+  
+  return template;
+});
 </script>
 
 <style scoped>

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

@@ -253,7 +253,7 @@ export const createCrudOptions = function ({ crudExpose, context}: CreateCrudOpt
 							const selection = context.selectedRows || [];
 							
 							if (!selection || selection.length === 0) {
-								warningMessage('请先选择要操作的申请');
+								warningMessage('请先选择要操作的数据');
 								return;
 							}
 							// 打开批量修改状态对话框
@@ -272,7 +272,7 @@ export const createCrudOptions = function ({ crudExpose, context}: CreateCrudOpt
 							const selection = context.selectedRows || [];
 							
 							if (!selection || selection.length === 0) {
-								warningMessage('请先选择要操作的申请');
+								warningMessage('请先选择要操作的数据');
 								return;
 							}
 

+ 60 - 2
src/views/JobApplication/list/index.vue

@@ -93,7 +93,25 @@
 			</div>
 			<div class="content">
 				<fs-crud ref="crudRef" v-bind="crudBinding">
-					<!-- 可以添加自定义插槽,如果需要 -->
+					<template #actionbar-right>
+						<div class="action-button-wrapper">
+							<el-upload
+								class="upload-demo"
+								:action="uploadUrl"
+								:headers="{
+									Authorization: `Bearer ${Session.get('token')}`
+								}"
+								:on-success="handleImportSuccess"
+								:on-error="handleImportError"
+								accept=".xlsx,.xls"
+							>
+								<el-button type="primary" size="small">
+									<el-icon><Upload /></el-icon>
+									导入
+								</el-button>
+							</el-upload>
+						</div>
+					</template>
 				</fs-crud>
 			</div>
 		</div>
@@ -109,7 +127,7 @@ import { useFs } from '@fast-crud/fast-crud';
 import { createCrudOptions } from './crud';
 import { GetPermission } from './api';
 import { handleColumnPermission } from '/@/utils/columnPermission';
-import { Grid, Clock, ArrowRight, Check, RefreshRight, Briefcase,Message } from '@element-plus/icons-vue';
+import { Grid, Clock, ArrowRight, Check, RefreshRight, Briefcase, Message, Upload } from '@element-plus/icons-vue';
 import BatchTagsDialog from './components/index.vue';
 import BatchStatusDialog from './components/BatchStatusDialog.vue';
 import smSnotification from './components/smSnotification.vue';
@@ -120,6 +138,9 @@ import { Session } from '/@/utils/storage';
 
 const route = useRoute();
 
+// 定义上传地址
+const uploadUrl = `${import.meta.env.VITE_API_URL}/api/job/application/import`;
+
 const { crudBinding, crudRef, crudExpose, crudOptions, resetCrudOptions } = useFs({ 
 	createCrudOptions,
 	context: {
@@ -296,6 +317,24 @@ const handleBatchStatusSuccess = () => {
 	fetchStatusSummary();
 };
 
+// 处理导入成功
+const handleImportSuccess = (response: any) => {
+	if (response.code === 2000) {
+		ElMessage.success('导入成功');
+		// 刷新数据和状态统计
+		crudExpose.doRefresh();
+		fetchStatusSummary();
+	} else {
+		ElMessage.error(response.message || '导入失败');
+	}
+};
+
+// 处理导入失败
+const handleImportError = (error: any) => {
+	console.error('导入失败:', error);
+	ElMessage.error('导入失败,请检查文件格式或网络连接');
+};
+
 // 页面打开后获取列表数据
 onMounted(async () => {
 	// 获取职位列表
@@ -472,4 +511,23 @@ const getPositionList = async () => {
 	flex: 1;
 	overflow: hidden;
 }
+
+.action-button-wrapper {
+	display: flex;
+	align-items: center;
+	height: 100%;
+	margin-left: 8px;
+}
+
+.action-button-wrapper :deep(.el-upload) {
+	display: flex;
+	align-items: center;
+}
+
+.action-button-wrapper :deep(.el-button) {
+	margin: 0;
+}
+:deep(.upload-demo){
+	height: 24px;
+}
 </style>

+ 9 - 0
src/views/position/detail/api.ts

@@ -231,4 +231,13 @@ export function GetQuestionDetail(id:any) {
 		url: `/api/system/interview_question/detail?question_id=${id}&tenant_id=${Session.get('tenant_id')}`,
 		method: 'get'
 	});
+}
+
+/* 获取已选择的职位问题数据 */
+export function GetSelectedApplications(params: any) {
+	return request({
+		url: '/api/system/job/questions',
+		method: 'get',
+		params: { ...params, tenant_id: Session.get('tenant_id') }
+	});
 }

+ 91 - 41
src/views/position/detail/index.vue

@@ -848,7 +848,7 @@
                     <div class="question-actions" v-if="element.question_form==1">
                       <div class="answer-limit">
                         <span class="answer-label">是否为红线题:</span>
-                        <el-select v-model="element.is_required_correct" @change="handleIsRequiredCorrectChange(element.id,element.is_required_correct)" size="small" placeholder="请选择">
+                        <el-select v-model="element.is_required_correct" :disabled="true" @change="handleIsRequiredCorrectChange(element.id,element.is_required_correct)" size="small" placeholder="请选择">
                           <el-option label="是" :value="true" />
                           <el-option label="否" :value="false" />
                         </el-select>
@@ -1267,9 +1267,10 @@
             <el-option label="开放问题" :value="0" />
             <el-option label="单选题" :value="1" />
             <el-option label="看图选答案" :value="3" />
-            <el-option label="多选题" value="multiple" />
-            <el-option label="填空题" value="fill" />
-            <el-option label="自言语" value="self" />
+            <el-option label="多选题" :value="2" />
+            <el-option label="填空题" :value="6" />
+            <el-option label="得分题" :value="4" />
+            <el-option label="追加型开放问题" :value="5"/>
           </el-select>
           <div class="form-tip">选择题目的形式:开放问题、单选题、多选题、填空题、自言语</div>
         </div>
@@ -2406,27 +2407,32 @@
     </el-dialog>
     <!-- 查看已选 -->
     <el-dialog
-     v-model="previewDialog"
-      title="预览"
+      v-model="previewDialog"
+      title="职位问题预览"
       width="60%"
       :close-on-click-modal="false">
-        <div class="selected-questions-preview" v-if="selectedQuestions.length > 0">
-            <div class="preview-title">已选择的题目({{ selectedQuestions.length }}):</div>
-            <div class="preview-list">
-              <el-tag
-                v-for="(question, index) in selectedQuestions"
-                :key="index"
-                class="preview-item"
-                closable
-                style="margin-bottom: 10px;"
-              >
-                {{ question.question }}
-              </el-tag>
-            </div>  
-          </div> 
-          <div class="preview-footer">
-            <el-button type="primary" @click="previewDialog = false">关闭</el-button>
-          </div>
+        <div class="selected-applications-preview">
+          <div class="preview-title">已绑定的问题({{ selectedApplications.length }}):</div>
+          <el-table :data="selectedApplications" style="width: 100%">
+            <el-table-column prop="question" label="问题内容" min-width="300" show-overflow-tooltip />
+            <!-- <el-table-column prop="competency_tag" label="胜任力标签" width="150">
+              <template #default="scope">
+                <el-tag size="small" type="info">{{ scope.row.competency_tag }}</el-tag>
+              </template>
+            </el-table-column>
+            <el-table-column prop="is_required_correct" label="是否红线题" width="100">
+              <template #default="scope">
+                <el-tag :type="scope.row.is_required_correct ? 'danger' : 'info'" size="small">
+                  {{ scope.row.is_required_correct ? '是' : '否' }}
+                </el-tag>
+              </template>
+            </el-table-column>
+            <el-table-column prop="score" label="分值" width="80" align="center" /> -->
+          </el-table>
+        </div>
+        <div class="preview-footer">
+          <el-button type="primary" @click="previewDialog = false">关闭</el-button>
+        </div>
     </el-dialog>
   </div>
 </template>
@@ -2444,7 +2450,7 @@ import { GetCompetencyList,GetQuestionList,GenerateQuestions,
   GetOpeningSpeech,GetVideo,BatchBind,BatchUnbind,UpdateObj,
   GenerateCompetency,SaveCompetency,GetPositionTags,
   UpdateQuestion,GetPositionQuestions,CreateCompetency,
-  BatchUpdateTags,GetQuestionDetail} from './api';
+  BatchUpdateTags,GetQuestionDetail,GetSelectedApplications} from './api';
 import draggable from 'vuedraggable';
 import { updateFieldConfig } from './utils';
 import type { ProfileFieldsConfig } from './types';
@@ -2726,10 +2732,26 @@ const handleLocationChange = (value: any) => {
   }
 };
 
-const previewDialog=ref(false)
+const previewDialog = ref(false)
+const selectedApplications = ref([])
+
 /* 预览已选 */
-const handleQuestionSelectPreview = () => {
+const handleQuestionSelectPreview = async () => {
   previewDialog.value = true;
+  try {
+    const response = await GetSelectedApplications({
+      page: 1,
+      limit: 100,
+      job_id: 22,
+      question_form: 0
+    });
+    if (response.data && response.data.items) {
+      selectedApplications.value = response.data.items;
+    }
+  } catch (error) {
+    console.error('获取职位申请数据失败:', error);
+    ElMessage.error('获取职位申请数据失败');
+  }
 }
 
 const handleIsRequiredCorrectChange = (id: number, value: boolean) => {
@@ -3443,7 +3465,7 @@ const addSelectedStepType = async (type: string, label: string) => {
     }).then((res:any) => {
       if(res.code == 2000) {
         recruitmentProcess[0].visible = true;
-        ElMessage.success('新增成功');
+        // ElMessage.success('新增成功');
       } else {
         ElMessage.error('删除失败');
       }
@@ -6173,10 +6195,10 @@ const saveBeforeStart = async () => {
       if (response.code === 2000) {
         // 创建成功后更新getConfigId
         getConfigId.value = response.data?.id || response.data;
-        ElMessage.success('开始前提示内容已创建');
+        ElMessage.success('开场词提示内容已创建');
         isEditingBeforeStart.value = false;
       } else {
-        ElMessage.error('开始前提示内容创建失败');
+        ElMessage.error('开场词提示内容创建失败');
       }
     } else {
       // getConfigId等于0时,调用UpdateConfig接口
@@ -6186,24 +6208,24 @@ const saveBeforeStart = async () => {
       });
       
       if (response.code === 2000) {
-        ElMessage.success('开始前提示内容已更新');
+        ElMessage.success('开场词提示内容已更新');
         isEditingBeforeStart.value = false;
         
         // 调用GetOpeningSpeech接口
         try {
           const params = { config_id: getConfigId.value };
           await GetOpeningSpeech(params);
-          console.log('开场生成成功');
+          console.log('开场生成成功');
         } catch (error) {
-          console.error('获取开场失败:', error);
-          ElMessage.warning('开场生成中,请稍后');
+          console.error('获取开场失败:', error);
+          ElMessage.warning('开场生成中,请稍后');
         }
       } else {
-        ElMessage.error('开始前提示内容更新失败');
+        ElMessage.error('开场词提示内容更新失败');
       }
     }
   } catch (error) {
-    console.error('保存开始前提示内容失败:', error);
+    console.error('保存开场词提示内容失败:', error);
     ElMessage.error('保存失败,请重试');
   }
 };
@@ -6757,13 +6779,13 @@ const handleDeleteDocument = (data: any) => {
 
 // 获取文档树数据
 const getTreeData = () => {
-	GetDocumentTree({}).then((ret: any) => {
+	GetDocumentTree({page:1,limit:100}).then((ret: any) => {
 		console.log('ret', ret);
 		const responseData = ret.data;
-		GetCategoryList({}).then((res: any) => {
+		GetCategoryList({page:1,limit:100}).then((res: any) => {
 			console.log('res', res);
 			const categoryList = res.data.items.filter((item: any) => 
-				!['技术能力', '服务意识', '职业素质','基本常识','色盲检测','内容铺垫','心理测试1'].includes(item.name)
+				!['技术能力', '服务意识', '职业素质','基本常识','色盲检测','内容铺垫','心理测试1','心理测试'].includes(item.name)
 			);
 			GetTagList({}).then((res: any) => {
 				console.log('res', res);
@@ -6884,13 +6906,13 @@ const handleNodeClick = async (data: any) => {
 }
 
 const getDFTreeData = () => {
-  GetDocumentTree({}).then((ret: any) => {
+  GetDocumentTree({page:1,limit:100}).then((ret: any) => {
 		console.log('ret', ret);
 		const responseData = ret.data;
-		GetCategoryList({}).then((res: any) => {
+		GetCategoryList({page:1,limit:100}).then((res: any) => {
 			console.log('res', res);
 			const categoryList = res.data.items.filter((item: any) => 
-				!['技术能力', '服务意识', '职业素质','基本常识','色盲检测','内容铺垫','红线题','健康情况','综合素质题'].includes(item.name)
+				['心理测试'].includes(item.name)
 			);
 			GetTagList({}).then((res: any) => {
 				console.log('res', res);
@@ -6918,6 +6940,34 @@ const getDFTreeData = () => {
 <style scoped>
 @import './index.css';
 
+.selected-applications-preview {
+  padding: 20px;
+}
+
+.preview-title {
+  font-size: 16px;
+  font-weight: bold;
+  margin-bottom: 20px;
+  color: #333;
+}
+
+.preview-footer {
+  margin-top: 20px;
+  text-align: right;
+}
+
+:deep(.el-table) {
+  margin-top: 15px;
+}
+
+:deep(.el-table th) {
+  background-color: #f5f7fa;
+}
+
+:deep(.el-tag) {
+  margin-right: 5px;
+}
+
 </style>
 <style lang="scss" scoped>
 /* 修改 checkbox 选中颜色 */

+ 10 - 2
src/views/questionBank/list/api.ts

@@ -127,5 +127,13 @@ export function AddFillQuestion(data:any) {
 	  method: 'post',
 	  data:{...data,tenant_id:Session.get('tenant_id')}
 	});
-  }
-  
+}
+
+// 更新评分标准
+export function UpdateScoringStandard(data: any) {
+	return request({
+		url: '/api/system/question_category/update_scoring_standard',
+		method: 'put',
+		data: { ...data, tenant_id: Session.get('tenant_id') }
+	});
+}

+ 130 - 0
src/views/questionBank/list/components/ScoringStandardDialog.vue

@@ -0,0 +1,130 @@
+<template>
+  <el-dialog
+    v-model="dialogVisible"
+    title="设置评分标准"
+    width="600px"
+    :close-on-click-modal="false"
+    :before-close="handleClose"
+  >
+    <el-form ref="formRef" :model="formData" label-width="100px">
+      <el-form-item label="评分说明">
+        <el-input
+          v-model="formData.scoring_reference"
+          type="textarea"
+          :rows="4"
+          placeholder="请输入评分标准说明,例如:【团队协作能力】1.优秀:xxxxxx。2.xxxx。3.一般:xxxxx。"
+        />
+      </el-form-item>
+     <!--  <el-form-item label="选项设置">
+        <div v-for="(option, index) in formData.options" :key="index" class="option-item">
+          <el-input
+            v-model="option.option_text"
+            placeholder="选项内容"
+            style="width: 200px; margin-right: 10px;"
+          />
+          <el-input-number
+            v-model="option.score"
+            :min="0"
+            :max="10"
+            placeholder="分值"
+            style="width: 120px;"
+          />
+        </div>
+      </el-form-item> -->
+    </el-form>
+    <template #footer>
+      <span class="dialog-footer">
+        <el-button @click="handleClose">取消</el-button>
+        <el-button type="primary" @click="handleSubmit">确认</el-button>
+      </span>
+    </template>
+  </el-dialog>
+</template>
+
+<script lang="ts" setup>
+import { ref, defineExpose } from 'vue';
+import { ElMessage } from 'element-plus';
+
+const dialogVisible = ref(false);
+const formRef = ref();
+const formData = ref({
+  scoring_reference: '',
+  options: [
+    { option_text: '无', score: 0 },
+    { option_text: '轻度', score: 1 },
+    { option_text: '中度', score: 2 },
+    { option_text: '偏重', score: 3 },
+    { option_text: '严重', score: 4 }
+  ]
+});
+
+const emit = defineEmits(['update']);
+
+const open = (data?: any) => {
+  dialogVisible.value = true;
+  if (data) {
+    formData.value = JSON.parse(JSON.stringify(data));
+  }
+};
+
+const handleClose = () => {
+  dialogVisible.value = false;
+  formData.value = {
+    scoring_reference: '',
+    options: [
+      { option_text: '无', score: 0 },
+      { option_text: '轻度', score: 1 },
+      { option_text: '中度', score: 2 },
+      { option_text: '偏重', score: 3 },
+      { option_text: '严重', score: 4 }
+    ]
+  };
+};
+
+const handleSubmit = async () => {
+  try {
+    // 验证所有选项都已填写
+    const isValid = formData.value.options.every(option => 
+      option.option_text.trim() !== '' && option.score !== undefined
+    );
+
+    if (!isValid) {
+      ElMessage.warning('请填写完整的选项内容和分值');
+      return;
+    }
+
+    // 触发更新事件
+    emit('update', formData.value);
+    
+    // 关闭对话框
+    handleClose();
+    
+    ElMessage.success('保存成功');
+  } catch (error) {
+    console.error('保存失败:', error);
+    ElMessage.error('保存失败,请重试');
+  }
+};
+
+defineExpose({
+  open
+});
+</script>
+
+<style lang="scss" scoped>
+.option-item {
+  display: flex;
+  align-items: center;
+  margin-bottom: 10px;
+
+  &:last-child {
+    margin-bottom: 0;
+  }
+}
+
+.dialog-footer {
+  display: flex;
+  justify-content: flex-end;
+  gap: 10px;
+}
+</style>

+ 49 - 2
src/views/questionBank/list/crud.tsx

@@ -887,21 +887,67 @@ export const createCrudOptions = function ({ crudExpose, context }: CreateCrudOp
 						helper: '选择题目的形式:开放问题、单选题、多选题、填空题、色盲题或追加型开放问题',
 					},
 				},
+				applicable_position_id:{
+					title: '适用职位',
+					search: { show: false,
+						size: 'small',
+						col:{ span:3},
+						/*  valueChange({ form, value, getColumn, mode }) {
+							if (value && value.length > 3) {
+								// 截断多余的选项
+								form.applicable_position_id= value.slice(0, 3);
+								// 可以添加提示
+							}
+							} */ },
+					type: 'dict-select',
+					column: {
+						show: false,
+						minWidth: 120,
+						maxTagCount: 1
+					},
+					dict: dict({
+						getData: async () => {
+							const res = await api.GetPositionList({page:1,limit:50,tenant_id:Session.get('tenant_id')});
+							console.log(res.data);
+							return res.data || [];
+						},
+						label: 'title',
+						value: 'id'
+					}),
+					form: {
+						show: false,
+						component: {
+						/* 	name: 'el-select', */
+						
+							props: {
+								
+								filterable: true,
+								placeholder: '请选择适用职位类型',
+								/* options: [
+									{ value: '0', label: '技术' },
+									{ value: '1', label: '管理' },
+								] */
+							}
+						},
+						helper: '选择题目适用的职位类型,可多选'
+					}
+				},
 				position_types: {
 					title: '适用职位',
-					search: { show: true,
+					search: { show: false,
 						size: 'small',
 						col:{ span:3},
 						 valueChange({ form, value, getColumn, mode }) {
 							if (value && value.length > 3) {
 								// 截断多余的选项
-								form.position_types = value.slice(0, 3);
+								form.position_types= value.slice(0, 3);
 								// 可以添加提示
 								/* Message.warning('最多只能选择3个职位类型'); */
 							}
 							} },
 					type: 'dict-select',
 					column: {
+					show:false,
 						minWidth: 120,
 						 maxTagCount: 1
 					},
@@ -915,6 +961,7 @@ export const createCrudOptions = function ({ crudExpose, context }: CreateCrudOp
 						value: 'id'
 					}),
 					form: {
+					show:false,
 						component: {
 						/* 	name: 'el-select', */
 							props: {

+ 50 - 1
src/views/questionBank/list/index.vue

@@ -23,6 +23,16 @@
 						</el-tooltip>
 						<span v-else>-</span>
 					</template>
+					<template #toolbar-right>
+						<el-button
+							v-if="showScoringButton"
+							type="primary"
+							size="small"
+							@click="handleSetScoring"
+						>
+							设置评分标准
+						</el-button>
+					</template>
 				</fs-crud>
 			</div>
 		</el-col>
@@ -33,6 +43,7 @@
 		<BatchTagsDialog ref="batchTagsDialogRef" :crudExpose="crudExpose" />
 		<BatchCategoryDialog ref="batchCategoryDialogRef" :crudExpose="crudExpose" />
 		<BatchCompetencyTagsDialog ref="batchCompetencyTagsDialogRef" :crudExpose="crudExpose" />
+		<ScoringStandardDialog ref="scoringDialogRef" @update="handleScoringUpdate" />
 		<el-drawer v-model="drawerVisible" title="添加分类" direction="rtl" size="500px" :close-on-click-modal="false" :before-close="handleDrawerClose">
 			<DocumentFormCom
 				v-if="drawerVisible"
@@ -48,6 +59,7 @@
 <script lang="ts" setup name="role">
 import { defineAsyncComponent, onMounted, ref } from 'vue';
 import { useFs } from '@fast-crud/fast-crud';
+import { ElMessageBox, ElMessage } from 'element-plus';
 import { createCrudOptions } from './crud';
 import { RoleDrawerStores } from './stores/RoleDrawerStores';
 import { RoleMenuBtnStores } from './stores/RoleMenuBtnStores';
@@ -67,8 +79,10 @@ const PermissionDrawerCom = defineAsyncComponent(() => import('./components/Role
 const BatchTagsDialog = defineAsyncComponent(() => import('./components/BatchTagsDialog.vue'));
 const BatchCategoryDialog = defineAsyncComponent(() => import('./components/BatchCategoryDialog.vue'));
 const BatchCompetencyTagsDialog = defineAsyncComponent(() => import('./components/BatchCompetencyTagsDialog.vue'));
+const ScoringStandardDialog = defineAsyncComponent(() => import('./components/ScoringStandardDialog.vue'));
 
 const batchTagsDialogRef = ref();
+const scoringDialogRef = ref();
 const batchCategoryDialogRef = ref();
 const batchCompetencyTagsDialogRef = ref();
 const drawerVisible = ref(false);
@@ -129,6 +143,36 @@ const { crudBinding, crudRef, crudExpose } = useFs({
 });
 
 const selectedCategoryId = ref(1);
+const showScoringButton = ref(false);
+
+// 处理设置评分标准按钮点击
+const handleSetScoring = () => {
+  // 打开评分标准设置对话框
+  scoringDialogRef.value?.open();
+};
+
+// 处理评分标准更新
+const handleScoringUpdate = async (data: any) => {
+  /* try {
+    // 调用API保存评分标准
+    const res = await UpdateScoringStandard({
+      category_id: selectedCategoryId.value,
+      scoring_reference: data.scoring_reference,
+      options: data.options
+    });
+
+    if (res.code === 2000) {
+      // 刷新列表
+      await crudExpose.doRefresh();
+      ElMessage.success('评分标准更新成功');
+    } else {
+      ElMessage.error(res.msg || '更新评分标准失败');
+    }
+  } catch (error) {
+    console.error('更新评分标准失败:', error);
+    ElMessage.error('更新评分标准失败,请重试');
+  } */
+};
 
 // 关闭抽屉
 const handleDrawerClose = (type: string) => {
@@ -172,6 +216,11 @@ const handleTreeClick = (node: any) => {
                    currentNodeId.startsWith('category_') ? 'category' :
                    currentNodeId.startsWith('tag_') ? 'tag' : 
                    firstLevelId;
+  
+  // 检查是否是心理测试分类
+  const currentNodeName = node?.firstLevel?.title || '';
+  console.log('currentNodeName', currentNodeName);
+  showScoringButton.value = currentNodeName === '心理测试';
  
   
   if (nodeType === 'open' || firstLevelId === 'root') {
@@ -231,7 +280,7 @@ const getTreeData = () => {
 		GetCategoryList({page:1,limit:50}).then((res: any) => {
 			console.log('res', res);
 			const categoryList = res.data.items.filter((item: any) => 
-				!['技术能力', '服务意识', '职业素质','基本常识','色盲检测','内容铺垫','心理测试','心理测试1'].includes(item.name)
+				!['技术能力', '服务意识', '职业素质','基本常识','色盲检测','内容铺垫','心理测试1'].includes(item.name)
 			);
 			GetTagList({}).then((res: any) => {
 				console.log('res', res);

+ 1 - 1
src/views/talent/list/api.ts

@@ -83,7 +83,7 @@ export function updateBatchTags(data: {
 
 export function getApplicationStatusSummary() {
 	return request({
-		url: '/api/system/job/application_status_summary/?tenant_id='+Session.get('tenant_id'),
+		url: '/api/system/talent_pool/status_summary/?tenant_id='+Session.get('tenant_id'),
 		method: 'get',
 	});
 }

+ 20 - 5
src/views/talent/list/index.vue

@@ -220,14 +220,17 @@ const fetchStatusSummary = async () => {
 		const data = res;
 		console.log(data)
 		if (data.code === 2000 && data.data) {
-			totalCount.value = data.data.total || 0;
+			/* totalCount.value = data.data.total || 0; */
 			
 			// 更新状态计数
 			if (data.data.status_data && Array.isArray(data.data.status_data)) {
+				// 重置总数
+				totalCount.value = 0;
+
 				data.data.status_data.forEach((item: any) => {
 					// 注意:API返回的status可能与前端定义的不完全一致,需要映射
 					const statusMap: Record<number, number> = {
-						0: 1, // API中的0对应前端的1(待面试)
+						1: 1, // API中的0对应前端的1(待面试)
 						2: 2, // 已面试
 						3: 3, // 已录用
 						4: 4  // 已拒绝
@@ -236,12 +239,24 @@ const fetchStatusSummary = async () => {
 					const frontendStatus = statusMap[item.status];
 					if (frontendStatus && frontendStatus in statusCounts) {
 						statusCounts[frontendStatus] = item.count;
+						// 累加到总数中
+						totalCount.value += item.count;
 					}
 				});
 			} else {
-				// 如果没有status_data,则使用单独的字段
-				statusCounts['1'] = data.data.pending || 0;
-				statusCounts['2'] = data.data.interviewed || 0;
+				// 如果没有status_data,则使用单独的字段并计算总数
+				const pending = data.data.pending || 0;
+				const interviewed = data.data.interviewed || 0;
+				const hired = data.data.hired || 0;
+				const rejected = data.data.rejected || 0;
+				
+				statusCounts[1] = pending;
+				statusCounts[2] = interviewed;
+				statusCounts[3] = hired;
+				statusCounts[4] = rejected;
+				
+				// 计算总数
+				totalCount.value = pending + interviewed + hired + rejected;
 				statusCounts['3'] = data.data.hired || 0;
 				statusCounts['4'] = data.data.rejected || 0;
 			}

+ 1 - 1
src/views/talent/overseas/api.ts

@@ -82,7 +82,7 @@ export function updateBatchTags(data: {
 
 export function getApplicationStatusSummary() {
 	return request({
-		url: '/api/system/job/application_status_summary/?tenant_id='+Session.get('tenant_id'),
+		url: '/api/system/talent_pool/status_summary/?tenant_id='+Session.get('tenant_id'),
 		method: 'get',
 	});
 }

+ 7 - 2
src/views/talent/overseas/index.vue

@@ -41,7 +41,7 @@
 							<el-icon><Grid /></el-icon>
 							<span>全部</span>
 						</div>
-						<div class="item-count">{{ totalCount }}</div>
+						<div class="item-count">{{ totalCount }}</div>
 					</div>
 					
 					<!-- 状态6 -->
@@ -165,10 +165,13 @@ const fetchStatusSummary = async () => {
 		const res = await getApplicationStatusSummary();
 		const data = res;
 		if (data.code === 2000 && data.data) {
-			totalCount.value = data.data.total || 0;
+			/* totalCount.value = data.data.total || 0; */
 			
 			// 更新状态计数
 			if (data.data.status_data && Array.isArray(data.data.status_data)) {
+					// 重置总数
+					totalCount.value = 0;
+
 				data.data.status_data.forEach((item: any) => {
 					if (item.status === 6) { // 状态6
 						statusCounts['6'] = item.count;
@@ -179,6 +182,8 @@ const fetchStatusSummary = async () => {
 					} else if (item.status === 2) { // 面试未通过
 						statusCounts['2'] = item.count;
 					}
+					// 累加到总数中
+					totalCount.value =statusCounts['6']+statusCounts['7'];
 				});
 			}
 		} else {