crud.tsx 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  1. import { CreateCrudOptionsProps, CreateCrudOptionsRet, AddReq, DelReq, EditReq, dict, compute } from '@fast-crud/fast-crud';
  2. import * as api from './api';
  3. import { dictionary } from '/@/utils/dictionary';
  4. import { successMessage } from '../../../utils/message';
  5. import { auth } from '/@/utils/authFunction';
  6. import { useRouter } from 'vue-router';
  7. import { ElMessage } from 'element-plus';
  8. export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProps): CreateCrudOptionsRet {
  9. const router = useRouter(); // 添加这行来获取router实例
  10. const pageRequest = async (query: any) => {
  11. // 确保查询参数正确传递
  12. api.GetDocumentTree({}).then((ret: any) => {
  13. // 构建请求参数,确保category参数被正确传递
  14. const params = {
  15. ...query,
  16. tenant_id: '1',
  17. // 如果 query.form 中有 category,使用它,否则使用 query.category
  18. category: (query.form && query.form.category) || query.category || '',
  19. job_id: ret.data[0].id
  20. };
  21. console.log('Request params:', params); // 添加日志以便调试
  22. return api.GetDocumentList(params);
  23. });
  24. };
  25. const editRequest = async ({ form, row }: any) => {
  26. return await api.UpdateDocument({
  27. ...form,
  28. id: row.id
  29. });
  30. };
  31. const delRequest = async ({ row }: any) => {
  32. return await api.DelDocument(row.id);
  33. };
  34. const addRequest = async ({ form }: any) => {
  35. return await api.AddDocument(form);
  36. };
  37. return {
  38. crudOptions: {
  39. request: {
  40. pageRequest,
  41. addRequest,
  42. editRequest,
  43. delRequest,
  44. },
  45. search: {
  46. show: true,
  47. onSearch: (params: any) => {
  48. console.log('Search params:', params);
  49. return params;
  50. },
  51. columns: {
  52. category: {
  53. title: "分类",
  54. search: { show: true, value: '' },
  55. type: 'text',
  56. column: { show: false } // 表格中不显示此列
  57. }
  58. }
  59. },
  60. rowHandle: {
  61. width: 250,
  62. buttons: {
  63. view: {
  64. size: 'small',
  65. click: ({ row }: any) => {
  66. const event = new CustomEvent('viewDocumentDetail', { detail: row });
  67. window.dispatchEvent(event);
  68. }
  69. },
  70. preview: {
  71. text: '预览',
  72. type: 'success',
  73. size: 'small',
  74. click: (row) => {
  75. // 检查文件路径是否存在
  76. if (!row.row || !row.row.file_path) {
  77. ElMessage.error('文件路径无效');
  78. return;
  79. }
  80. const filePath = row.row.file_path;
  81. // 获取文件扩展名
  82. const fileType = row.row.file_type;
  83. // 支持的文件类型列表
  84. const supportedTypes = ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'];
  85. if (!supportedTypes.includes(fileType)) {
  86. ElMessage.warning(`暂不支持预览该文件类型: ${fileType}`);
  87. return;
  88. }
  89. // 使用window.open在新窗口中打开预览页面
  90. const previewUrl = `/#/preview?url=${encodeURIComponent(filePath)}&type=${fileType}`;
  91. window.open(previewUrl, '_blank');
  92. }
  93. },
  94. edit: {
  95. type: 'primary',
  96. size: 'small',
  97. },
  98. remove: {
  99. type: 'danger',
  100. size: 'small',
  101. }
  102. }
  103. },
  104. form: {
  105. view: {
  106. disabled: true,
  107. display: 'text'
  108. }
  109. },
  110. columns: {
  111. /* _index: {
  112. title: '序号',
  113. form: { show: false },
  114. column: {
  115. type: 'index',
  116. align: 'center',
  117. width: '70px',
  118. columnSetDisabled: true, //禁止在列设置中选择
  119. },
  120. }, */
  121. position_id: {
  122. title: '职位',
  123. search: { show: true },
  124. type: 'dict-select',
  125. column: {
  126. value: '1',
  127. minWidth: 120,
  128. show: false,
  129. },
  130. form: { show: false },
  131. },
  132. question_id: {
  133. title: 'ID',
  134. search: { show: false },
  135. column: {
  136. value: '1',
  137. show: false
  138. },
  139. form: { show: false },
  140. },
  141. id: {
  142. title: 'ID',
  143. column: { show: false },
  144. search: { show: false },
  145. form: { show: false },
  146. },
  147. question: {
  148. title: '题目内容',
  149. search: { show: true },
  150. column: {
  151. minWidth: 120,
  152. sortable: 'custom',
  153. },
  154. form: {
  155. rules: [{ required: true, message: '题目内容必填' }],
  156. component: {
  157. placeholder: '请输入题目内容',
  158. },
  159. },
  160. },
  161. question_type: {
  162. title: '问题类型',
  163. search: { show: true },
  164. type: 'dict-select',
  165. column: {
  166. minWidth: 100,
  167. },
  168. dict: dict({
  169. data: [
  170. { value: 1, label: '专业技能' },
  171. { value: 2, label: '通用能力' },
  172. { value: 3, label: '个人特质' }
  173. ]
  174. }),
  175. form: {
  176. rules: [{ required: true, message: '问题类型必填' }],
  177. component: {
  178. placeholder: '请选择问题类型',
  179. },
  180. helper: '选择问题的类型分类',
  181. },
  182. },
  183. question_form: {
  184. title: '题目形式',
  185. search: { show: true },
  186. type: 'dict-select',
  187. column: {
  188. minWidth: 100,
  189. },
  190. dict: dict({
  191. data: [
  192. { value: 0, label: '开放问题' },
  193. { value: 1, label: '单选题' },
  194. { value: 2, label: '多选题' }
  195. ]
  196. }),
  197. form: {
  198. rules: [{ required: true, message: '题目形式必填' }],
  199. component: {
  200. placeholder: '请选择题目形式',
  201. onChange: ({ form }: { form: any }) => {
  202. // 重置相关字段
  203. if (form.question_form === 1) {
  204. // 单选题
  205. form.options = [{ option_text: '', is_correct: false, sort: 1 }, { option_text: '', is_correct: false, sort: 2 }];
  206. } else if (form.question_form === 2) {
  207. // 多选题
  208. form.options = [{ option_text: '', is_correct: false, sort: 1 }, { option_text: '', is_correct: false, sort: 2 }];
  209. } else {
  210. // 开放问题
  211. form.options = [];
  212. }
  213. }
  214. },
  215. helper: '选择题目的形式:开放问题、单选题或多选题',
  216. },
  217. },
  218. position_types: {
  219. title: '适用职位',
  220. search: { show: true },
  221. type: 'dict-select',
  222. column: {
  223. minWidth: 120,
  224. },
  225. dict: dict({
  226. data: [
  227. { value: '0', label: '技术' },
  228. { value: '1', label: '管理' },
  229. ]
  230. }),
  231. form: {
  232. component: {
  233. /* name: 'el-select', */
  234. props: {
  235. multiple: true,
  236. filterable: true,
  237. placeholder: '请选择适用职位类型',
  238. /* options: [
  239. { value: '0', label: '技术' },
  240. { value: '1', label: '管理' },
  241. ] */
  242. }
  243. },
  244. helper: '选择题目适用的职位类型,可多选'
  245. }
  246. },
  247. recommended_duration: {
  248. title: '建议时长(秒)',
  249. search: { show: false },
  250. column: {
  251. minWidth: 100,
  252. },
  253. form: {
  254. component: {
  255. name: 'el-input-number',
  256. props: {
  257. min: 10,
  258. max: 600,
  259. step: 10
  260. }
  261. },
  262. helper: '建议回答此题目的时长,单位为秒'
  263. }
  264. },
  265. difficulty: {
  266. title: '难度等级',
  267. search: { show: true },
  268. type: 'dict-select',
  269. column: {
  270. minWidth: 80,
  271. },
  272. dict: dict({
  273. data: [
  274. { value: 1, label: '初级' },
  275. { value: 2, label: '中级' },
  276. { value: 3, label: '高级' }
  277. ]
  278. }),
  279. form: {
  280. rules: [{ required: true, message: '难度等级必填' }],
  281. helper: '选择题目的难度级别'
  282. },
  283. },
  284. is_system: {
  285. title: '系统题目',
  286. search: { show: true },
  287. column: {
  288. width: 80,
  289. component: {
  290. name: 'el-switch'
  291. }
  292. },
  293. form: {
  294. component: {
  295. name: 'el-switch',
  296. props: {
  297. activeText: '是',
  298. inactiveText: '否'
  299. }
  300. },
  301. helper: '是否为系统预设题目'
  302. }
  303. },
  304. status: {
  305. title: '状态',
  306. search: { show: true },
  307. type: 'dict-select',
  308. column: {
  309. width: 80,
  310. /* component: {
  311. name: 'fs-dict-label',
  312. props: {
  313. dict: dict({
  314. data: [
  315. { value: 0, label: '停用' },
  316. { value: 1, label: '启用' }
  317. ]
  318. })
  319. }
  320. } */
  321. },
  322. dict: dict({
  323. data: [
  324. { value: 0, label: '停用' },
  325. { value: 1, label: '启用' }
  326. ]
  327. }),
  328. form: {
  329. rules: [{ required: true, message: '状态必填' }],
  330. component: {
  331. placeholder: '请选择状态',
  332. },
  333. helper: '题目的启用状态'
  334. },
  335. },
  336. sort: {
  337. title: '排序',
  338. search: { show: false },
  339. column: {
  340. width: 80,
  341. },
  342. form: {
  343. component: {
  344. name: 'el-input-number',
  345. props: {
  346. min: 1,
  347. max: 999
  348. }
  349. },
  350. helper: '题目的排序值,值越小排序越靠前'
  351. }
  352. },
  353. option_items: {
  354. title: '选项列表',
  355. search: { show: false },
  356. column: { show: false },
  357. form: {
  358. show: compute(({ form }) => {
  359. return form && (form.question_form === 1 || form.question_form === 2);
  360. }),
  361. component: {
  362. name: 'el-card',
  363. children: {
  364. default: ({ form }) => {
  365. // 确保options数组已初始化
  366. if (!form.options) {
  367. form.options = [];
  368. }
  369. return (
  370. <div>
  371. <div class="option-header" style="display: flex; margin-bottom: 10px; font-weight: bold;">
  372. <span style="flex: 1;">选项内容</span>
  373. <span style="width: 80px; text-align: center;">是否正确</span>
  374. </div>
  375. {form.options.map((option: any, index: number) => (
  376. <div class="option-item" key={index} style="display: flex; align-items: center; margin-bottom: 10px;">
  377. <el-input
  378. v-model={option.option_text}
  379. placeholder="请输入选项内容"
  380. style="flex: 1; margin-right: 10px;"
  381. />
  382. <el-tooltip
  383. content="设置为正确答案"
  384. placement="top"
  385. effect="light"
  386. >
  387. <div
  388. onClick={() => {
  389. if (form.question_form === 1) {
  390. // 单选题:只能有一个正确答案
  391. form.options.forEach((item: any, idx: number) => {
  392. item.is_correct = (idx === index);
  393. });
  394. } else {
  395. // 多选题:可以有多个正确答案
  396. option.is_correct = !option.is_correct;
  397. }
  398. }}
  399. style="cursor: pointer; width: 80px; text-align: center;"
  400. >
  401. {form.question_form === 1 ? (
  402. // 单选题使用单选按钮
  403. <el-radio
  404. modelValue={option.is_correct}
  405. label={true}
  406. />
  407. ) : (
  408. // 多选题使用复选框
  409. <el-checkbox
  410. modelValue={option.is_correct}
  411. />
  412. )}
  413. </div>
  414. </el-tooltip>
  415. </div>
  416. ))}
  417. <div style="display: flex; justify-content: space-between; margin-top: 10px;">
  418. <el-button
  419. type="primary"
  420. onClick={() => {
  421. // 确保options数组已初始化
  422. if (!form.options) {
  423. form.options = [];
  424. }
  425. // 添加新选项时自动设置排序值
  426. const sort = form.options.length > 0 ?
  427. Math.max(...form.options.map((o: any) => o.sort || 0)) + 1 : 1;
  428. form.options.push({ option_text: '', is_correct: false, sort });
  429. }}
  430. >
  431. 添加选项
  432. </el-button>
  433. {form.options.length > 2 && (
  434. <el-button
  435. type="danger"
  436. onClick={() => {
  437. form.options.pop();
  438. }}
  439. >
  440. 删除最后一项
  441. </el-button>
  442. )}
  443. </div>
  444. </div>
  445. )
  446. }
  447. }
  448. },
  449. helper: compute(({ form }) => {
  450. if (form.question_form === 1) {
  451. return '添加单选题的选项,并标记正确答案(只能有一个正确答案)';
  452. } else if (form.question_form === 2) {
  453. return '添加多选题的选项,并标记正确答案(可以有多个正确答案)';
  454. }
  455. return '';
  456. })
  457. }
  458. },
  459. answer_explanation: {
  460. title: '答案解析',
  461. search: { show: false },
  462. column: { show: false },
  463. form: {
  464. component: {
  465. name: 'el-input',
  466. type: 'textarea',
  467. rows: 4,
  468. placeholder: '请输入答案解析'
  469. },
  470. },
  471. },
  472. },
  473. }
  474. };
  475. };