12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598 |
- import { CreateCrudOptionsProps, CreateCrudOptionsRet, AddReq, DelReq, EditReq, dict, compute } from '@fast-crud/fast-crud';
- import * as api from './api';
- import { dictionary } from '/@/utils/dictionary';
- import { successMessage, warningMessage } from '../../../utils/message';
- import { auth } from '/@/utils/authFunction';
- import { ref, onMounted, watch } from 'vue';
- import { ElMessage } from 'element-plus';
- import { Session } from '/@/utils/storage';
- // 在文件顶部添加全局接口声明
- declare global {
- interface Window {
- competencyTagsOptions?: any[];
- }
- }
- /**
- *
- * @param crudExpose:index传递过来的示例
- * @param context:index传递过来的自定义参数
- * @returns
- */
- export const createCrudOptions = function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
- const pageRequest = async (query: any) => {
- // 如果存在 question 搜索值,将其赋值给 keyword
- console.log('query', query);
- if (query.question) {
- query.keyword = query.question;
- delete query.question_tag;
- delete query.question; // 删除原有的 question 参数
- }
- const params = {
- ...query,
- question_category: query.category||query.question_category,
- /* question_tag: query.tag, */
- tenant_id: Session.get('tenant_id')
- }
- console.log('params', params);
- return await api.GetList(params);
- };
- const editRequest = async ({ form, row }: EditReq) => {
- form.id = row.id;
-
- // 处理胜任力标签配置
- if (form.competency_tags && form.competency_tags.length > 0 && form.competency_tags_config) {
- form.competency_tags = form.competency_tags_config.map((config: any) => ({
- id: config.id,
- weight: config.weight || 100,
- importance: config.importance || 1,
- remark: config.remark || ''
- }));
- } else {
- form.competency_tags_config = [];
- }
-
- // 调用更新题目的接口
- const editResult = await api.UpdateObj(form);
-
- // 如果更新成功且题目形式为0(开放题)或5,异步触发视频生成
- if (editResult.code === 2000 && (form.question_form === 0 || form.question_form === 5)) {
- // 使用 setTimeout 将视频生成请求放入下一个事件循环
- /* setTimeout(async () => {
- try {
- // 构造视频生成请求参数
- const videoParams = {
- video_url: "http://data.qicai321.com/minlong/32ae7e1f-042f-4ee5-b234-be34d98d70e6.mp4",
- text: form.question,
- question_id: form.id,
- guidance_scale: 2.0,
- inference_steps: 20,
- seed: 1247
- };
- // 调用视频生成接口
- const videoResult = await fetch(`${import.meta.env.VITE_API_URL_MINLONG}/queue/process/text/`, {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json'
- },
- body: JSON.stringify(videoParams)
- });
- if (!videoResult.ok) {
- console.warn('数字人视频生成请求失败:', await videoResult.text());
- ElMessage({
- type: 'warning',
- message: '数字人视频生成请求失败,但不影响题目的更新'
- });
- } else {
- ElMessage({
- type: 'success',
- message: '题目已更新,数字人视频正在重新生成中,请稍后查看'
- });
- }
- } catch (error) {
- console.error('调用数字人视频生成接口失败:', error);
- ElMessage({
- type: 'warning',
- message: '数字人视频生成失败,但题目已成功更新'
- });
- }
- }, 0); */
- }
- return editResult;
- };
- const delRequest = async ({ row }: DelReq) => {
- return await api.DelObj(row.id);
- };
- const addRequest = async ({ form }: AddReq) => {
- // 处理胜任力标签配置
- if (form.competency_tags && form.competency_tags.length > 0 && form.competency_tags_config) {
- form.competency_tags = form.competency_tags_config.map((config: any) => ({
- id: config.id,
- weight: config.weight || 100,
- importance: config.importance || 1,
- remark: config.remark || ''
- }));
- } else {
- form.competency_tags_config = [];
- }
-
- // 根据题目类型调用不同的接口
- let addResult;
- if (form.question_form === 6) { // 填空题
- addResult = await api.AddFillQuestion(form);
- } else {
- addResult = await api.AddObj(form);
- }
-
- // 如果添加成功且题目形式为0(开放题)或5,异步触发视频生成
- if (addResult.code === 2000 && (form.question_form === 0 || form.question_form === 5)) {
- // 使用 setTimeout 将视频生成请求放入下一个事件循环
- /* setTimeout(async () => {
- try {
- // 构造视频生成请求参数
- const videoParams = {
- video_url: "http://data.qicai321.com/minlong/32ae7e1f-042f-4ee5-b234-be34d98d70e6.mp4",
- text: form.question,
- question_id: addResult.data.id,
- guidance_scale: 2.0,
- inference_steps: 20,
- seed: 1247
- };
- // 调用视频生成接口http://192.168.66.101:7861
- const videoResult = await fetch(`${import.meta.env.VITE_API_URL_MINLONG}/queue/process/text/`, {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json'
- },
- body: JSON.stringify(videoParams)
- });
- if (!videoResult.ok) {
- console.warn('数字人视频生成请求失败:', await videoResult.text());
- ElMessage({
- type: 'warning',
- message: '数字人视频生成请求失败,但不影响题目的保存'
- });
- } else {
- ElMessage({
- type: 'success',
- message: '题目已保存,数字人视频正在生成中,请稍后查看'
- });
- }
- } catch (error) {
- console.error('调用数字人视频生成接口失败:', error);
- ElMessage({
- type: 'warning',
- message: '数字人视频生成失败,但题目已成功保存'
- });
- }
- }, 0); */
- }
- return addResult;
- };
- /* // 修改分类和标签数据获取方式
- const categoryOptions = ref<Array<{value: number, label: string}>>([]);
- const tagOptions = ref<Array<{value: number, label: string}>>([]);
-
- // 获取分类数据
- const fetchCategories = async () => {
- try {
- const res = await api.GetcategoryList({page:1, limit:1000, tenant_id:1});
- if (res.code === 0 && res.data && res.data.items) {
- categoryOptions.value = res.data.items;
- }
- } catch (error) {
- console.error('获取分类数据失败', error);
- }
- };
-
- // 获取标签数据
- const fetchTags = async (categoryId?: number) => {
- try {
- const params = {
- page: 1,
- limit: 1000,
- tenant_id: 1
- };
- if (categoryId) {
- params.category_id = categoryId;
- }
- const res = await api.GetTagList(params);
- if (res.code === 0 && res.data && res.data.items) {
- tagOptions.value = res.data.items;
- }
- } catch (error) {
- console.error('获取标签数据失败', error);
- }
- }; */
-
- // 初始化时获取分类数据
- /* onMounted(() => {
- fetchCategories();
- fetchTags();
- }); */
- // 添加批量更新标签的方法
- const batchUpdateTags = async (questionIds: number[], tagIds: number[]) => {
- try {
- const res = await api.BatchUpdateTags({
- question_ids: questionIds,
- tags: tagIds,
- tenant_id: 1
- });
- if (res.code === 0) {
- successMessage('批量更新标签成功');
- // 刷新列表
- crudExpose.doRefresh();
- }
- } catch (error) {
- console.error('批量更新标签失败', error);
- }
- };
- // 添加批量更新分类的方法
- const batchUpdateCategory = async (questionIds: number[], categoryId: number) => {
- try {
- const res = await api.BatchUpdateCategory({
- question_ids: questionIds,
- category_id: categoryId,
- tenant_id: Session.get('tenant_id')
- });
- if (res.code === 0) {
- successMessage('批量更新分类成功');
- // 刷新列表
- crudExpose.doRefresh();
- }
- } catch (error) {
- console.error('批量更新分类失败', error);
- }
- };
- return {
- crudOptions: {
- toolbar:{
- buttons:{
- search:{show:false},
- // 刷新按钮
- refresh:{show:false},
- // 紧凑模式
- compact:{show:false},
- // 导出按钮
- export:{
- text: '导出',
- type: 'primary',
- size: 'small',
- icon: 'upload',
- circle: false,
- display: true,
- show:false
- },
- // 列设置按钮
- columns:{
- show:false
- },
- }
- },
- request: {
- pageRequest,
- addRequest,
- editRequest,
- delRequest,
- },
- pagination: {
- show: true,
- },
- // 添加搜索表单配置
- search: {
- col: { span: 3 },
- show: true,
- autoSearch:false,
- buttons: {
- search: {
- size: 'small', // 设置查询按钮大小为small
- },
- reset: {
- size: 'small', // 设置重置按钮大小为small
- }
- }
- },
- actionbar: {
- buttons: {
- add: {
- size: 'small',
- show: auth('role:Create'),
- },
- // 添加批量绑定标签按钮
- batchBindTags: {
- text: '批量绑定标签',
- type: 'primary',
- size: 'small',
- show: true,
- order: 2,
- click: () => {
- // 使用存储的选中行
- const selection = context.selectedRows || [];
- console.log('选中的行:', selection);
-
- if (!selection || selection.length === 0) {
- warningMessage('请先选择要操作的题目');
- return;
- }
- // 打开批量绑定标签对话框
- context.openBatchTagsDialog(selection);
- },
- },
- // 添加批量设置分类按钮
- batchSetCategory: {
- text: '批量设置分类',
- type: 'primary',
- show: true,
- size: 'small',
- order: 3,
- click: () => {
- // 使用存储的选中行
- const selection = context.selectedRows || [];
- console.log('选中的行:', selection);
-
- if (!selection || selection.length === 0) {
- warningMessage('请先选择要操作的题目');
- return;
- }
- // 打开批量设置分类对话框
- context.openBatchCategoryDialog(selection);
- },
- },
- batchBindCompetencyTags: {
- text: '批量绑定胜任力标签',
- type: 'primary',
- size: 'small',
- show: true,
- order: 4,
- click: () => {
- const selection = context.selectedRows || [];
-
- if (!selection || selection.length === 0) {
- warningMessage('请先选择要操作的题目');
- return;
- }
- // 打开批量绑定胜任力标签对话框
- context.openBatchCompetencyTagsDialog(selection);
- },
- },
- },
- },
- rowHandle: {
- //固定右侧
- fixed: 'right',
- width: 259,
- buttons: {
- view: {
- show: true,
- size: 'small',
- icon:"View",
- type: 'text',
- },
- edit: {
- show: auth('role:Update'),
- size: 'small',
- icon:"Edit",
- type: 'text',
- },
- remove: {
- show: auth('role:Delete'),
- size: 'small',
- type: 'text',
- icon:"Delete",
- },
- // 添加生成数字人视频按钮
- /* generateVideo: {
- text: '生成视频',
- type: 'text',
- size: 'small',
- show: ({ row }) => {
- // 只在题目形式为开放题(0)或追加型开放题(5)时显示
- return row.question_form === 0 || row.question_form === 5;
- },
- click: async ({ row }) => {
- try {
- // 构造视频生成请求参数
- const videoParams = {
- video_url: "http://data.qicai321.com/minlong/32ae7e1f-042f-4ee5-b234-be34d98d70e6.mp4",
- text: row.question,
- question_id: row.id,
- guidance_scale: 2.0,
- inference_steps: 20,
- seed: 1247
- };
- // 调用视频生成接口
- const videoResult = await fetch('http://192.168.66.101:7861/queue/process/text/', {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json'
- },
- body: JSON.stringify(videoParams)
- });
- if (!videoResult.ok) {
- console.warn('数字人视频生成请求失败:', await videoResult.text());
- ElMessage({
- type: 'error',
- message: '视频生成请求失败'
- });
- } else {
- ElMessage({
- type: 'info',
- message: '数字人视频正在生成中...'
- });
- }
- } catch (error) {
- console.error('调用数字人视频生成接口失败:', error);
- ElMessage({
- type: 'error',
- message: '视频生成请求失败'
- });
- }
- }
- } */
- },
- },
- form: {
- col: { span: 24 },
- labelWidth: '100px',
- wrapper: {
- is: 'el-dialog',
- width: '600px',
- },
- },
- columns: {
- _selection: {
- title: '选择',
- form: { show: false },
- column: {
- type: 'selection',
- align: 'center',
- width: 50,
- fixed: 'left',
- columnSetDisabled: true,
- },
- },
- id: {
- title: 'ID',
- column: { show: true ,width:80,},
- search: { show: false },
- form: { show: false },
- },
- question: {
- title: '题目内容',
- search: {
- show: true,
- size: 'small',
- col: { span: 3 },
- component: {
- name: 'el-input',
- props: {
- placeholder: '请输入题目内容搜索',
- clearable: true
- }
- }
- },
- column: {
- showOverflowTooltip: true,
- width: 300,
- sortable: 'custom',
- },
- form: {
- rules: [{ required: true, message: '题目内容必填' }],
- component: {
- placeholder: '请输入题目内容',
- },
- },
- },
- competency_tags:{
- title: '胜任力标签',
- search: {
- show: true,
- size: 'small',
- component: {
- props: {
- multiple: false,
- filterable: true,
- }
- },
- col:{ span:3 },
- },
- type: 'dict-select',
- column: {
- minWidth: 230,
- component: {
- name: 'fs-component',
- render: ({ row }: { row: any }) => {
- if (!row.competency_tags || row.competency_tags.length === 0) return <span>-</span>;
-
- const displayTags = row.competency_tags.slice(0, 2);
- const remainingCount = row.competency_tags.length - 2;
-
- return (
- <div style="display: flex; gap: 4px; align-items: center;">
- {displayTags.map((tag: any) => (
- <el-tag
- key={tag.id}
- type="warning"
- effect="plain"
- size="mini"
- style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap;"
- title={tag.name}
- >
- {tag.name.length > 4 ? tag.name.slice(0, 4) + '...' : tag.name}
- </el-tag>
- ))}
- {remainingCount > 0 && (
- <el-tooltip
- placement="top"
- effect="light"
- popper-class="tag-tooltip"
- >
- {{
- default: () => (
- <el-tag
- type="info"
- effect="plain"
- size="mini"
- >
- +{remainingCount}
- </el-tag>
- ),
- content: () => (
- <div>
- <div style="font-weight: bold; margin-bottom: 5px">剩余{remainingCount}个标签:</div>
- {row.competency_tags.slice(2).map((tag: any) => (
- <div key={tag.id} style="margin: 3px 0">{tag.name}</div>
- ))}
- </div>
- )
- }}
- </el-tooltip>
- )}
- </div>
- );
- }
- }
- },
- dict: dict({
- getData: async () => {
- const res = await api.GetCompetencyList({page:1, limit:100, tenant_id:Session.get('tenant_id')});
- window.competencyTagsOptions = res.data.items || [];
- return res.data.items;
- },
- label: 'name',
- value: 'id'
- }),
- form: {
- component: {
- props: {
- multiple: true,
- filterable: true,
- placeholder: '请选择胜任力标签'
- },
- value: compute(({ form }) => {
- if (!form.competency_tags) return [];
- console.log('form.competency_tags', form.competency_tags);
- // 如果是数组但元素是对象,提取id
- if (Array.isArray(form.competency_tags)) {
- const ids = form.competency_tags.map((tag: any) => {
- if (typeof tag === 'object' && tag !== null) {
- // 同时更新 competency_tags_config
- if (!form.competency_tags_config) {
- form.competency_tags_config = [];
- form.competency_tags = [];
- }
-
- // 检查配置是否已存在
- const existingConfig = form.competency_tags_config.find(
- (config: any) => config.id === tag.id
- );
-
- if (!existingConfig) {
- form.competency_tags_config.push({
- id: tag.id,
- competency_name: tag.name,
- weight: tag.weight || 100,
- importance: tag.importance || 1,
- remark: ''
- });
-
- form.competency_tags.push(tag.id);
- }
-
- return tag.id;
- }
- return tag;
- });
- return ids;
- }
-
- return form.competency_tags;
- }),
- onValueChange: ({ value, form }: { value: any[], form: any }) => {
- // 保存选中的ID数组
- form.competency_tags = value;
-
- // 同步更新competency_tags_config
- if (!form.competency_tags_config) {
- form.competency_tags_config = [];
- }
-
- // 获取当前已有的配置ID
- const existingConfigIds = form.competency_tags_config.map((config: any) => config.id);
-
- // 从全局变量获取胜任力标签选项数据
- const competencyOptions = window.competencyTagsOptions || [];
-
- // 添加新选择的标签配置
- value.forEach((tagId: number) => {
- if (!existingConfigIds.includes(tagId)) {
- // 查找标签信息
- const tagInfo = competencyOptions.find((tag: any) => tag.id === tagId);
- if (tagInfo) {
- form.competency_tags_config.push({
- id: tagId,
- competency_name: tagInfo.name,
- weight: tagInfo.weight || 100,
- importance: tagInfo.importance || 1,
- remark: ''
- });
- }
- }
- });
-
- // 移除已不存在的标签配置
- form.competency_tags_config = form.competency_tags_config.filter(
- (config: any) => value.includes(config.id)
- );
- }
- },
- helper: '选择题目关联的胜任力标签,可多选'
- }
- },
- competency_tags_config: {
- title: '胜任力配置',
- search: { show: false },
- column: { show: false },
- form: {
- show: compute(({ form }) => {
- // 只有当选择了胜任力标签时才显示配置
- return form && form.competency_tags && form.competency_tags.length > 0;
- }),
- component: {
- name: 'el-card',
- children: {
- default: ({ form }: { form: any }) => {
- // 确保competency_tags_config数组已初始化
- if (!form.competency_tags_config) {
- form.competency_tags_config = [];
- }
-
- // 使用ref标记是否已经处理过,避免重复处理
- const processed = ref(false);
-
- // 使用onMounted确保只在组件挂载时执行一次
- onMounted(() => {
- if (!processed.value && form.competency_tags && form.competency_tags.length > 0) {
- updateCompetencyConfig();
- processed.value = true;
- }
- });
-
- // 监听competency_tags变化,但避免无限循环
- watch(() => [...(form.competency_tags || [])], (newTags, oldTags) => {
- // 只有当标签真正变化时才更新配置
- if (JSON.stringify(newTags) !== JSON.stringify(oldTags)) {
- updateCompetencyConfig();
- }
- });
-
- // 抽取更新配置的逻辑到单独的函数
- const updateCompetencyConfig = () => {
- // 获取当前已有的配置ID
- const existingConfigIds = form.competency_tags_config.map((config: any) => config.id);
-
- // 创建新的配置数组
- const newConfigs = [...form.competency_tags_config];
-
- // 从全局变量获取胜任力标签选项数据
- const competencyOptions = window.competencyTagsOptions || [];
-
- // 添加新选择的标签配置
- form.competency_tags.forEach((tagId: number) => {
- if (!existingConfigIds.includes(tagId)) {
- // 查找标签名称
- const tagName = competencyOptions.find((tag: any) => tag.id === tagId)?.name || '未知标签';
-
- // 添加新配置
- newConfigs.push({
- id: tagId,
- competency_name: tagName,
- weight: 100, // 默认权重为100%
- importance: 1, // 默认重要性为1
- remark: '' // 默认备注为空
- });
- }
- });
-
- // 移除已不存在的标签配置
- const filteredConfigs = newConfigs.filter(
- (config: any) => form.competency_tags.includes(config.id)
- );
-
- // 一次性更新配置数组
- form.competency_tags_config = filteredConfigs;
- };
-
- // 渲染表格
- return (
- <div>
- <el-table border style="width: 100%" data={form.competency_tags_config}>
- <el-table-column label="标签" width="200">
- {{
- default: ({ row }: { row: any }) => (
- <span>{row.competency_name}</span>
- )
- }}
- </el-table-column>
- <el-table-column label="权重" width="100">
- {{
- default: ({ row }: { row: any }) => (
- <div class="weight-input" style="display: flex; align-items: center;">
- <el-input-number
- v-model={row.weight}
- min={0}
- max={100}
- step={1}
- precision={0}
- controls={false}
- style="width: calc(100% - 20px)"
- />
- <span style="margin-left: 4px;">%</span>
- </div>
- )
- }}
- </el-table-column>
- <el-table-column label="级别" width="100">
- {{
- default: ({ row }: { row: any }) => (
- <el-input-number
- v-model={row.importance}
- min={1}
- controls={false}
- style="width: 100%"
- />
- )
- }}
- </el-table-column>
- {/* <el-table-column label="备注">
- {{
- default: ({ row }: { row: any }) => (
- <el-input
- v-model={row.remark}
- placeholder="请输入备注"
- />
- )
- }}
- </el-table-column> */}
- </el-table>
- </div>
- );
- }
- }
- },
- helper: '配置每个胜任力标签的权重、重要性和备注'
- }
- },
-
- /* question_type: {
- title: '问题类型',
- search: { show: true },
- type: 'dict-select',
- column: {
- minWidth: 100,
- },
- dict: dict({
- data: [
- { value: 1, label: '专业技能' },
- { value: 2, label: '通用能力' },
- { value: 3, label: '个人特质' }
- ]
- }),
- form: {
- rules: [{ required: true, message: '问题类型必填' }],
- component: {
- placeholder: '请选择问题类型',
- },
- helper: '选择问题的类型分类',
- },
- }, */
- question_form: {
- title: '题目形式',
- search: { show: true,
- size: 'small',
- col:{ span:3},
- },
- type: 'dict-select',
- column: {
- minWidth: 120,
- },
- dict: dict({
- // 使用API方式获取数据
- getData: async () => {
- const res = await api.GetQuestionTypeList();
- // 返回question_forms数组
- return res.data.question_forms || [];
- },
- label: 'label',
- value: 'value'
- }),
- form: {
- rules: [{ required: true, message: '题目形式必填' }],
- component: {
- placeholder: '请选择题目形式',
- onChange: ({ form }: { form: any }) => {
- // 重置相关字段
- if (form.question_form === 1) {
- // 单选题
- form.options = [{ option_text: '', is_correct: false, sort: 1 }, { option_text: '', is_correct: false, sort: 2 }];
- } else if (form.question_form === 2) {
- // 多选题
- form.options = [{ option_text: '', is_correct: false, sort: 1 }, { option_text: '', is_correct: false, sort: 2 }];
- } else if (form.question_form === 4) {
- // 得分题 - 初始化五个评分选项
- form.options = [
- { option_text: '无', score: 0, sort: 1 },
- { option_text: '轻度', score: 1, sort: 2 },
- { option_text: '中度', score: 2, sort: 3 },
- { option_text: '偏重', score: 3, sort: 4 },
- { option_text: '严重', score: 4, sort: 5 }
- ];
- // 初始化评分说明
- if (!form.scoring_reference) {
- form.scoring_reference = '该评分反映了症状表现的频率与严重程度。';
- }
- } else if (form.question_form === 6) {
- // 填空题
- form.blank_answer_template = [
- { blank_index: 1, correct_answer: '', score: 5 }
- ];
- // 初始化评分说明
- if (!form.scoring_reference) {
- form.scoring_reference = '根据答案的准确性评分';
- }
- } else {
- // 开放问题
- form.options = [];
- }
- }
- },
- helper: '选择题目的形式:开放问题、单选题、多选题、填空题、色盲题或追加型开放问题',
- },
- },
- position_types: {
- title: '适用职位',
- search: { show: true,
- size: 'small',
- col:{ span:3}, },
- type: 'dict-select',
- column: {
- 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: {
- component: {
- /* name: 'el-select', */
- props: {
- multiple: true,
- filterable: true,
- placeholder: '请选择适用职位类型',
- /* options: [
- { value: '0', label: '技术' },
- { value: '1', label: '管理' },
- ] */
- }
- },
- helper: '选择题目适用的职位类型,可多选'
- }
- },
- category_id: {
- title: '分类',
- search: { show: true,
- size: 'small',
- col:{ span:2}, },
- type: 'dict-select',
- column: {
- minWidth: 120,
- component: {
- // 自定义渲染组件,显示彩色标签
- // name: 'fs-component',
- render: ({ row }: { row: any }) => {
- if (!row.category || row.category.length === 0) return <span>-</span>;
-
- return (
- <el-tag
- key={row.category.id}
- type="warning"
- effect="plain"
- size="mini"
- style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap;"
- >
- {row.category.name.length > 4 ? row.category.name.slice(0, 4) + '...' : row.category.name}
- </el-tag>
- );
- }
- }
- },
- dict: dict({
- // 使用API方式获取数据
- getData: async () => {
- const res = await api.GetcategoryList({page:1, limit:50, tenant_id:Session.get('tenant_id')});
- return res.data.items;
- },
- label: 'name',
- value: 'id'
- }),
- form: {
- // rules: [{ required: true, message: '题目分类必填' }],
- component: {
- placeholder: '请选择题目分类',
- /* onChange: ({ value }: { value: number }) => {
- // 当分类变化时,重新获取对应的标签
- fetchTags(value);
- } */
- },
- helper: '选择所属的分类'
- },
- },
- question_tags:{
- title: '标签',
- search: {
- show: true,
- size: 'small',
- col:{ span:3 },
- component: {
- props: {
- multiple: false, // 在搜索表单中使用单选模式
- filterable: true,
- placeholder: '请选择标签搜索'
- }
- }
- },
- type: 'dict-select',
- column: {
- show: false,
- minWidth: 220,
- },
- dict: dict({
- // 使用API方式获取数据
- getData: async () => {
- const res = await api.GetTagList({page:1, limit:50, tenant_id:Session.get('tenant_id')});
- return res.data.items;
- },
- label: 'name',
- value: 'id'
- }),
- form: {
- show:false,
- component: {
-
- props: {
- multiple: true, // 在编辑表单中保持多选
- filterable: true,
- placeholder: '请选择标签'
- }
- },
- helper: '选择题目关联的标签,可多选'
- }
- },
- tags:{
- title: '标签',
- search: {
- show: false,
- size: 'small',
- col:{ span:3},
- component: {
- props: {
- multiple: false, // 在搜索表单中使用单选模式
- filterable: true,
- placeholder: '请选择标签搜索'
- }
- }
- },
- type: 'dict-select',
- column: {
- minWidth: 220,
- component: {
- name: 'fs-component',
- render: ({ row }: { row: any }) => {
- if (!row.tags || row.tags.length === 0) return <span>-</span>;
-
- const displayTags = row.tags.slice(0, 2); // 只取前两个标签
- const remainingCount = row.tags.length - 2; // 计算剩余标签数量
-
- return (
- <div style="display: flex; gap: 4px; align-items: center;">
- {displayTags.map((tag: any) => (
- <el-tag
- key={tag.id}
- type="warning"
- effect="plain"
- size="mini"
- style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap;"
- title={tag.name}
- >
- {tag.name.length > 4 ? tag.name.slice(0, 4) + '...' : tag.name}
- </el-tag>
- ))}
- {remainingCount > 0 && (
- <el-tooltip
- placement="top"
- effect="light"
- popper-class="tag-tooltip"
- >
- {{
- default: () => (
- <el-tag
- type="info"
- effect="plain"
- size="mini"
- >
- +{remainingCount}
- </el-tag>
- ),
- content: () => (
- <div>
- <div style="font-weight: bold; margin-bottom: 5px">剩余{remainingCount}个标签:</div>
- {row.tags.slice(2).map((tag: any) => (
- <div key={tag.id} style="margin: 3px 0">{tag.name}</div>
- ))}
- </div>
- )
- }}
- </el-tooltip>
- )}
- </div>
- );
- }
- }
- },
- dict: dict({
- // 使用API方式获取数据
- getData: async () => {
- const res = await api.GetTagList({page:1, limit:50, tenant_id:Session.get('tenant_id')});
- return res.data.items;
- },
- label: 'name',
- value: 'id'
- }),
- form: {
- component: {
- props: {
- multiple: true, // 在编辑表单中保持多选
- filterable: true,
- placeholder: '请选择标签'
- }
- },
- helper: '选择题目关联的标签'
- }
- },
- recommended_duration: {
- title: '建议时长(秒)',
- search: { show: false },
- column: {
- minWidth: 100,
- },
- form: {
- value: 60,
- component: {
- name: 'el-input-number',
- props: {
- min: 10,
- max: 600,
- step: 10
- }
- },
- helper: '建议回答此题目的时长,单位为秒'
- }
- },
- /* difficulty: {
- title: '难度等级',
- search: { show: true },
- type: 'dict-select',
- column: {
- minWidth: 80,
- },
- dict: dict({
- data: [
- { value: 1, label: '初级' },
- { value: 2, label: '中级' },
- { value: 3, label: '高级' }
- ]
- }),
- form: {
- rules: [{ required: true, message: '难度等级必填' }],
- helper: '选择题目的难度级别'
- },
- }, */
- is_system: {
- title: '系统题目',
- search: { show: false },
- type: 'dict-select',
- column: {
- width: 100,
- /* component: {
- name: 'fs-component',
- render: ({ row }: { row: any }) => {
- return row.is_system ?
- <el-tag type="success" size="small">是</el-tag> :
- <el-tag type="info" size="small">否</el-tag>;
- }
- } */
- },
- dict: dict({
- data: [
- { value: true, label: '是' },
- { value: false, label: '否' }
- ]
- }),
- form: {
- value: false,
- component: {
- placeholder: '请选择是否为系统题目'
- },
- helper: '是否为系统预设题目'
- }
- },
- status: {
- title: '状态',
- search: { show: true,
- size: 'small',
- col:{ span:2},},
- type: 'dict-select',
- column: {
- width: 80,
- },
- dict: dict({
- data: [
- { value: 0, label: '停用' },
- { value: 1, label: '启用' }
- ]
- }),
- form: {
- value: 1,
- rules: [{ required: true, message: '状态必填' }],
- component: {
- placeholder: '请选择状态',
- },
- helper: '题目的启用状态'
- },
- },
- // 添加红线问题字段
- is_required_correct: {
- title: '红线问题',
- search: { show: false,
- size: 'small',
- col:{ span:2}, },
- type: 'dict-select',
- column: {
- width: 100,
- component: {
- name: 'fs-component',
- render: ({ row }: { row: any }) => {
- // 只有单选题和多选题才显示红线问题状态
- if (row.question_form !== 1 && row.question_form !== 2) {
- return <span>-</span>;
- }
- return row.is_required_correct ?
- <el-tag type="danger" size="small">是</el-tag> :
- <el-tag type="info" size="small">否</el-tag>;
- }
- }
- },
- dict: dict({
- data: [
- { value: true, label: '是' },
- { value: false, label: '否' }
- ]
- }),
- form: {
- value: false,
- show: compute(({ form }) => {
- // 只有单选题和多选题才显示红线问题选项
- return form && (form.question_form === 1 || form.question_form === 2);
- }),
- component: {
- placeholder: '请选择是否为红线问题'
- },
- helper: '红线问题是指必须回答正确的题目,否则可能导致面试失败'
- }
- },
- sort: {
- title: '排序',
- search: { show: false },
- column: {
- width: 80,
- },
- form: {
- component: {
- name: 'el-input-number',
- props: {
- min: 1,
- max: 999
- }
- },
- helper: '题目的排序值,值越小排序越靠前'
- }
- },
- option_items: {
- title: '选项列表',
- search: { show: false },
- column: { show: false },
- form: {
- show: compute(({ form }) => {
- return form && (form.question_form === 1 || form.question_form === 2 || form.question_form === 4);
- }),
- component: {
- name: 'el-card',
- children: {
- default: ({ form }: { form: any }) => {
- // 确保options数组已初始化
- if (!form.options) {
- form.options = [];
- }
-
- // 心理评估题的选项渲染
- if (form.question_form === 4) {
- return (
- <div>
- <div class="option-header" style="display: flex; margin-bottom: 10px; font-weight: bold;">
- <span style="flex: 1;">选项内容</span>
- <span style="width: 120px; text-align: center;">分值</span>
- </div>
- {form.options.map((option: any, index: number) => (
- <div class="option-item" key={index} style="display: flex; align-items: center; margin-bottom: 10px;">
- <el-input
- v-model={option.option_text}
- placeholder="请输入选项内容"
- style="flex: 1; margin-right: 10px;"
- />
- <el-input-number
- v-model={option.score}
- min={0}
- max={10}
- style="width: 120px;"
- placeholder="分值"
- />
- </div>
- ))}
- <div style="display: flex; justify-content: space-between; margin-top: 10px;">
- <el-button
- type="primary"
- onClick={() => {
- if (!form.options) {
- form.options = [];
- }
- const sort = form.options.length > 0 ?
- Math.max(...form.options.map((o: any) => o.sort || 0)) + 1 : 1;
- form.options.push({ option_text: '', score: 0, sort });
- }}
- >
- 添加选项
- </el-button>
-
- {form.options.length > 2 && (
- <el-button
- type="danger"
- onClick={() => {
- form.options.pop();
- }}
- >
- 删除最后一项
- </el-button>
- )}
- </div>
- </div>
- );
- }
-
- // 单选题和多选题的选项渲染(原有逻辑)
- return (
- <div>
- <div class="option-header" style="display: flex; margin-bottom: 10px; font-weight: bold;">
- <span style="flex: 1;">选项内容</span>
- <span style="width: 80px; text-align: center;">是否正确</span>
- </div>
- {form.options.map((option: any, index: number) => (
- <div class="option-item" key={index} style="display: flex; align-items: center; margin-bottom: 10px;">
- <el-input
- v-model={option.option_text}
- placeholder="请输入选项内容"
- style="flex: 1; margin-right: 10px;"
- />
- <el-tooltip
- content="设置为正确答案"
- placement="top"
- effect="light"
- >
- <div
- onClick={() => {
- if (form.question_form === 1) {
- // 单选题:只能有一个正确答案
- form.options.forEach((item: any, idx: number) => {
- item.is_correct = (idx === index);
- });
- } else {
- // 多选题:可以有多个正确答案
- option.is_correct = !option.is_correct;
- }
- }}
- style="cursor: pointer; width: 80px; text-align: center;"
- >
- {form.question_form === 1 ? (
- // 单选题使用单选按钮
- <el-radio
- modelValue={option.is_correct}
- label={true}
- />
- ) : (
- // 多选题使用复选框
- <el-checkbox
- modelValue={option.is_correct}
- />
- )}
- </div>
- </el-tooltip>
- </div>
- ))}
- <div style="display: flex; justify-content: space-between; margin-top: 10px;">
- <el-button
- type="primary"
- onClick={() => {
- // 确保options数组已初始化
- if (!form.options) {
- form.options = [];
- }
- // 添加新选项时自动设置排序值
- const sort = form.options.length > 0 ?
- Math.max(...form.options.map((o: any) => o.sort || 0)) + 1 : 1;
- form.options.push({ option_text: '', is_correct: false, sort });
- }}
- >
- 添加选项
- </el-button>
-
- {form.options.length > 2 && (
- <el-button
- type="danger"
- onClick={() => {
- form.options.pop();
- }}
- >
- 删除最后一项
- </el-button>
- )}
- </div>
- </div>
- )
- }
- }
- },
- helper: compute(({ form }) => {
- if (form.question_form === 1) {
- return '添加单选题的选项,并标记正确答案(只能有一个正确答案)';
- } else if (form.question_form === 2) {
- return '添加多选题的选项,并标记正确答案(可以有多个正确答案)';
- } else if (form.question_form === 4) {
- return '添加心理评估题的选项,并设置每个选项的分值';
- }
- return '';
- })
- }
- },
- scoring_reference: {
- title: '评分标准',
- search: { show: false },
- column: { show: false },
- form: {
- component: {
- name: 'el-input',
- type: 'textarea',
- rows: 4,
- placeholder: compute(({ form }) => {
- if (form && form.question_form === 4) {
- return '请输入评分标准说明';
- }
- return '请输入评分标准说明';
- })
- },
- helper: compute(({ form }) => {
- if (form && form.question_form === 4) {
- return '评分标准说明,例如:【团队协作能力】1.优秀:xxxxxx。2.xxxx。3.一般:xxxxx。';
- }
- return '评分标准说明,例如:【团队协作能力】1.优秀:xxxxxx。2.xxxx。3.一般:xxxxx。';
- })
- },
- },
- digital_human_video_url:{
- title: '视频是否生成',
- search: { show: false },
- column: {
- width: 120,
- component: {
- name: 'fs-component',
- render: ({ row }: { row: any }) => {
- return row.digital_human_video_url ?
- <el-tag type="success" size="small">是</el-tag> :
- <el-tag type="info" size="small">否</el-tag>;
- }
- }
- },
- form: {
- show: false // 在表单中不显示此字段,通常由系统自动生成
- }
- },
- blank_answer_template: {
- title: '填空答案模板',
- search: { show: false },
- column: { show: false },
- form: {
- show: compute(({ form }) => {
- return form && form.question_form === 6;
- }),
- component: {
- name: 'el-card',
- children: {
- default: ({ form }: { form: any }) => {
- // 确保blank_answer_template数组已初始化
- if (!form.blank_answer_template) {
- form.blank_answer_template = [{ blank_index: 1, correct_answer: '', score: 5 }];
- }
- // 计算题目中的填空数量
- const blankCount = (form.question || '').split('___').length - 1;
- // 如果填空数量变化,更新模板
- if (blankCount > 0 && form.blank_answer_template.length !== blankCount) {
- form.blank_answer_template = Array.from({ length: blankCount }, (_, i) => ({
- blank_index: i + 1,
- correct_answer: '',
- score: 5
- }));
- }
- return (
- <div>
- <div class="blank-header" style="display: flex; margin-bottom: 10px; font-weight: bold;">
- <span style="width: 80px;">填空序号</span>
- <span style="flex: 1;">正确答案</span>
- <span style="width: 120px; text-align: center;">分值</span>
- </div>
- {form.blank_answer_template.map((blank: any, index: number) => (
- <div class="blank-item" key={index} style="display: flex; align-items: center; margin-bottom: 10px;">
- <span style="width: 80px;">{blank.blank_index}</span>
- <el-input
- v-model={blank.correct_answer}
- placeholder="请输入正确答案"
- style="flex: 1; margin: 0 10px;"
- />
- <el-input-number
- v-model={blank.score}
- min={0}
- max={100}
- style="width: 120px;"
- placeholder="分值"
- />
- </div>
- ))}
- <div style="color: #666; font-size: 12px; margin-top: 10px;">
- 提示:在题目中使用"___"(三个下划线)表示填空位置,系统会自动识别填空数量
- </div>
- </div>
- );
- }
- }
- },
- helper: '设置每个填空的正确答案和分值'
- }
- }
-
- },
- // 确保表格配置正确
- table: {
- selection: true,
- onSelectionChange: (selection: any[]) => {
- // 存储选中的行到一个全局变量中
- context.selectedRows = selection;
- },
- },
- },
- };
- };
- // 导出批量更新标签方法,供组件使用
- export const useBatchUpdateTags = (crudExpose: any) => {
- const batchUpdateTags = async (questionIds: number[], tagIds: number[]) => {
- try {
- const res = await api.BatchUpdateTags({
- question_ids: questionIds,
- tags: tagIds,
- tenant_id: Session.get('tenant_id')
- });
- if (res.code === 0) {
- successMessage('批量更新标签成功');
- // 刷新列表
- crudExpose.doRefresh();
- }
- } catch (error) {
- console.error('批量更新标签失败', error);
- }
- };
-
- return { batchUpdateTags };
- };
- // 导出批量更新分类方法,供组件使用
- export const useBatchUpdateCategory = (crudExpose: any) => {
- const batchUpdateCategory = async (questionIds: number[], categoryId: number) => {
- try {
- const res = await api.BatchUpdateCategory({
- question_ids: questionIds,
- category_id: categoryId,
- tenant_id: Session.get('tenant_id')
- });
- if (res.code === 0) {
- successMessage('批量更新分类成功');
- // 刷新列表
- crudExpose.doRefresh();
- }
- } catch (error) {
- console.error('批量更新分类失败', error);
- }
- };
-
- return { batchUpdateCategory };
- };
- // 导出批量更新胜任力标签方法,供组件使用
- export const useBatchUpdateCompetencyTags = (crudExpose: any) => {
- const batchUpdateCompetencyTags = async (questionIds: number[], competencyTags: any[]) => {
- try {
- const res = await api.BatchUpdateCompetencyTags({
- question_ids: questionIds,
- competency_tags: competencyTags,
- tenant_id: Session.get('tenant_id')
- });
- if (res.code === 0) {
- successMessage('批量更新胜任力标签成功');
- // 刷新列表
- crudExpose.doRefresh();
- }
- } catch (error) {
- console.error('批量更新胜任力标签失败', error);
- }
- };
-
- return { batchUpdateCompetencyTags };
- };
|