Commit 45201ff771c7a07458ed34784868470bb03e00f1

Authored by 王强
1 parent 68e1e5e7

优化 题库设置,添加 适用范围 展示,添加 通用审批流程交互,并对接接口;

src/pages/ehr/ProgramOfStudy/QuestionBank/api.ts
1 1 import request from "@/utils/request";
2 2 import { ABILITY_HOST } from "@/utils/host";
3   -import { common } from "@/typing/common";
4 3 import { http } from "@/typing/http";
5 4  
6 5 /** 获取题库列表 */
7   -export function getQuestionBankListApi(params: QuestionBank.QueryParams) {
8   - return request.get<common.Page<QuestionBank.List[]>>(
9   - `${ABILITY_HOST}/erp/question/factory/list`,
10   - { params }
11   - );
  6 +export function getQuestionBankListApi(
  7 + params: QuestionBank.QueryParams
  8 +): http.PromisePageResp<QuestionBank.List> {
  9 + return request.get(`${ABILITY_HOST}/erp/question/factory/list`, { params });
12 10 }
13 11  
14 12 /** 保存题库 */
... ... @@ -24,21 +22,20 @@ export function deleteQuestionBankApi(id: number) {
24 22 }
25 23  
26 24 /** 获取题目列表 */
27   -export function getQuestionListApi(params: { factoryId: number }) {
28   - return request.get<common.Page<QuestionBank.Question[]>>(
29   - `${ABILITY_HOST}/erp/question/info/list`,
30   - { params }
31   - );
  25 +export function getQuestionListApi(params: {
  26 + factoryId: number;
  27 +}): http.PromisePageResp<QuestionBank.Question> {
  28 + return request.get(`${ABILITY_HOST}/erp/question/info/list`, { params });
32 29 }
33 30  
34 31 /** 保存题目 */
35 32 export function saveQuestionApi(params: QuestionBank.Question) {
36   - return request.post<any>(`${ABILITY_HOST}/erp/question/info/save`, params);
  33 + return request.post<string>(`${ABILITY_HOST}/erp/question/info/save`, params);
37 34 }
38 35  
39 36 /** 删除题目 */
40 37 export function deleteQuestionApi(id: number) {
41   - return request.get<any>(`${ABILITY_HOST}/erp/question/info/del`, {
  38 + return request.get<string>(`${ABILITY_HOST}/erp/question/info/del`, {
42 39 params: { id },
43 40 });
44 41 }
... ...
src/pages/ehr/ProgramOfStudy/QuestionBank/components/QuestionBankItem/MultipleChoice.tsx
... ... @@ -45,7 +45,7 @@ export default function MultipleChoice({ item, edit = false, index }: Props) {
45 45  
46 46 const formInit = () => {
47 47 form.setFieldsValue({ ...initContent, rightAnswer: initContent.rightAnswer!.split(',') });
48   - }
  48 + };
49 49  
50 50 // 确定添加/修改 题
51 51 const onOk = () => {
... ... @@ -56,6 +56,7 @@ export default function MultipleChoice({ item, edit = false, index }: Props) {
56 56 }
57 57 const params: QuestionBank.Question = {
58 58 ...content,
  59 + draftId,
59 60 title: val.title,
60 61 rightAnswer: val.rightAnswer.sort().join(','),
61 62 };
... ... @@ -70,8 +71,8 @@ export default function MultipleChoice({ item, edit = false, index }: Props) {
70 71 setIsAddFinish(true);
71 72 }).catch(error => message.error(error.message));
72 73 setContent({ ...content, id: content.index, title: val.title, rightAnswer: val.rightAnswer });
73   - })
74   - }
  74 + });
  75 + };
75 76  
76 77 // 添加选项
77 78 const addOption = () => {
... ... @@ -83,7 +84,7 @@ export default function MultipleChoice({ item, edit = false, index }: Props) {
83 84 setContent({ ...content, answerItemList: [...content.answerItemList!, param] });
84 85 setAddInputValue('');
85 86 // setIsAdd(false);
86   - }
  87 + };
87 88  
88 89 // 删除选项
89 90 const delOption = (key: string) => {
... ... @@ -96,7 +97,7 @@ export default function MultipleChoice({ item, edit = false, index }: Props) {
96 97 // 如果删除选项编号在正确答案之前,则重置选项编号
97 98 const rightLabels = content.answerItemList!.filter(ans => rightAnswer.filter((ra: string) => ra !== key).includes(ans.itemNo)).map(ans => ans.answerItem);
98 99 if (rightAnswer.findIndex((ra: string) => +ra > +key) > -1) form.setFieldsValue({ rightAnswer: answerItemList.filter(ans => rightLabels.includes(ans.answerItem)).map(ans => ans.key) });
99   - }
  100 + };
100 101  
101 102 // 删除题目
102 103 const delQuestion = (item: QuestionBank.Question, index: number) => {
... ... @@ -105,7 +106,7 @@ export default function MultipleChoice({ item, edit = false, index }: Props) {
105 106 addModalContents.length > 0 && setAddModalContents(addModalContents.filter(content => content.index !== index));
106 107 TYPE === 1 ? setQuestionLoading(true) : setDraftLoading(true);
107 108 }).catch(error => message.error(error.message));
108   - }
  109 + };
109 110  
110 111 // 取消编辑题目
111 112 const cancel = () => {
... ... @@ -118,7 +119,7 @@ export default function MultipleChoice({ item, edit = false, index }: Props) {
118 119 setAddModalContents(addModalContents.filter(cont => cont.index !== content.index));
119 120 setIsAddFinish(true);
120 121 }
121   - }
  122 + };
122 123  
123 124 return (
124 125 <Row
... ... @@ -136,64 +137,68 @@ export default function MultipleChoice({ item, edit = false, index }: Props) {
136 137 >
137 138 {isBatchDelete ? <Checkbox style={{ marginRight: 10 }} checked={isChecked} /> : null}
138 139 <Card style={{ flex: 1, marginBottom: 10, borderColor: isChecked ? '#1890FF' : '' }}>
139   - <Row justify='space-between' align='top'>
  140 + <Row justify="space-between" align="top">
140 141 <Col span={2}>{!addVisible && (index !== undefined && typeof index === 'number') && <h1>{TYPE === 1 ? index + 1 + (current! - 1) * pageSize! : count}</h1>}</Col>
141 142 <Col span={18}>
142 143 <Form form={form}>
143   - <Form.Item name='title' rules={[{ required: isEdit, message: '请输入题目' }]}>
  144 + <Form.Item name="title" rules={[{ required: isEdit, message: '请输入题目' }]}>
144 145 {!isEdit ?
145 146 <span style={{ fontSize: 16, display: 'block' }}>{content.title}</span> :
146   - <Input placeholder='请输入题目' allowClear />}
  147 + <Input placeholder="请输入题目" allowClear />}
147 148 </Form.Item>
148   - <Form.Item name='rightAnswer' rules={[{ required: isEdit, message: '请选择正确答案' }]}>
149   - <Checkbox.Group className='multipleChoice' disabled={!isEdit} >
150   - {content.answerItemList!.map(ans => <Checkbox key={ans.itemNo} value={ans.itemNo} style={{ width: '100%', marginBottom: 10 }}>
151   - <div style={{ display: 'flex', justifyContent: 'space-between', width: '100%' }}>
152   - <span className="span_word_break" style={{ display: 'block', width: '95%' }}>{ans.itemNo}.&nbsp;&nbsp;{ans.answerItem}</span>
153   - {isEdit && <Popconfirm title={`确定删除?`} onConfirm={() => delOption(ans.itemNo!)}><Button type='link' style={{ display: 'block' }} icon={<DeleteOutlined />} /></Popconfirm>}
154   - </div>
155   - </Checkbox>
  149 + <Form.Item name="rightAnswer" rules={[{ required: isEdit, message: '请选择正确答案' }]}>
  150 + <Checkbox.Group className="multipleChoice" disabled={!isEdit}>
  151 + {content.answerItemList!.map(ans => (
  152 + <Checkbox key={ans.itemNo} value={ans.itemNo} style={{ width: '100%', marginBottom: 10 }}>
  153 + <div style={{ display: 'flex', justifyContent: 'space-between', width: '100%' }}>
  154 + <span className="span_word_break" style={{ display: 'block', width: '95%' }}>{ans.itemNo}.&nbsp;&nbsp;{ans.answerItem}</span>
  155 + {isEdit && <Popconfirm title="确定删除?" onConfirm={() => delOption(ans.itemNo!)}><Button type="link" style={{ display: 'block' }} icon={<DeleteOutlined />} /></Popconfirm>}
  156 + </div>
  157 + </Checkbox>
  158 +)
156 159 )}
157 160 </Checkbox.Group>
158 161 </Form.Item>
159 162 </Form>
160   - <Row justify='space-between' style={{ height: 42 }}>
  163 + <Row justify="space-between" style={{ height: 42 }}>
161 164 <Col span={6} style={{ justifyContent: 'center', alignItems: 'center', display: 'flex' }}>
162   - {isEdit && <Button disabled={!isEdit} type='link' icon={isAdd ? <CloseOutlined /> : <PlusOutlined />} style={{ padding: '4px 0' }} onClick={() => setIsAdd(!isAdd)}>{isAdd ? '取消添加选项' : '添加单个选项'}</Button>}
  165 + {isEdit && <Button disabled={!isEdit} type="link" icon={isAdd ? <CloseOutlined /> : <PlusOutlined />} style={{ padding: '4px 0' }} onClick={() => setIsAdd(!isAdd)}>{isAdd ? '取消添加选项' : '添加单个选项'}</Button>}
163 166 </Col>
164 167 <Col span={18}>
165   - {isAdd && <Input
  168 + {isAdd && (
  169 + <Input
166 170 style={{ width: '100%' }}
167   - placeholder='请输入选项'
  171 + placeholder="请输入选项"
168 172 allowClear
169 173 value={addInputValue}
170 174 onChange={e => setAddInputValue(e.target.value.trim())}
171 175 onPressEnter={() => addOption()}
172 176 suffix={
173   - <Button type='link' icon={<PlusCircleOutlined />} onClick={() => addOption()} />
174   - } />
175   - }
  177 + <Button type="link" icon={<PlusCircleOutlined />} onClick={() => addOption()} />
  178 + }
  179 + />
  180 +)}
176 181 </Col>
177 182 </Row>
178 183 </Col>
179 184 <Col span={4}>
180 185 {TYPE === 2 && !isBatchDelete ? (
181   - <Row justify='end'>
  186 + <Row justify="end">
182 187 {/* {!isEdit && <Button disabled type='default' style={{ marginRight: 10 }} icon={<DragOutlined />} />} */}
183 188 {!isEdit ?
184   - <Button type='default' style={{ marginRight: 10 }} icon={<FormOutlined />} onClick={() => setIsEdit(!isEdit)} /> :
185   - <Button type='default' style={{ marginRight: 10 }} icon={<CheckOutlined />} onClick={() => onOk()} />}
186   - {!isEdit ?
187   - <Popconfirm title={`确定删除?`} onConfirm={() => delQuestion(content!, content.index!)}>
188   - <Button type='default' icon={<DeleteOutlined />} danger />
189   - </Popconfirm> :
190   - <Button type='default' icon={<CloseOutlined />} onClick={cancel} />
191   - }
  189 + <Button type="default" style={{ marginRight: 10 }} icon={<FormOutlined />} onClick={() => setIsEdit(!isEdit)} /> :
  190 + <Button type="default" style={{ marginRight: 10 }} icon={<CheckOutlined />} onClick={() => onOk()} />}
  191 + {!isEdit ? (
  192 + <Popconfirm title="确定删除?" onConfirm={() => delQuestion(content!, content.index!)}>
  193 + <Button type="default" icon={<DeleteOutlined />} danger />
  194 + </Popconfirm>
  195 + ) :
  196 + <Button type="default" icon={<CloseOutlined />} onClick={cancel} />}
192 197 </Row>
193 198 ) : null}
194 199 </Col>
195 200 </Row>
196 201 </Card>
197 202 </Row>
198   - )
  203 + );
199 204 }
200 205 \ No newline at end of file
... ...
src/pages/ehr/ProgramOfStudy/QuestionBank/components/QuestionBankList/QuestionBankModal.tsx
1 1 /*
2 2 * @Date: 2021-07-14 10:54:47
3 3 * @LastEditors: wangqiang@feewee.cn
4   - * @LastEditTime: 2022-12-09 19:06:15
  4 + * @LastEditTime: 2023-02-10 09:13:23
5 5 */
6 6 import React, { useEffect, useState } from "react";
7 7 import { Modal, Form, Input, message, TreeSelect } from "antd";
8 8 import { useStore } from "../../index";
9 9 import { saveQuestionBankApi, saveDraftApi } from "../../api";
10   -import { LabeledValue } from "antd/lib/select";
11 10 import RangeRoleSelector from "@/pages/ehr/ProgramOfStudy/components/RangeRoleSelector";
  11 +import SelectBrandOrSeries from '@/pages/ehr/ProgramOfStudy/components/SelectBrandOrSeries';
12 12  
13 13 export default function QuestionBankModal() {
14 14 const {
... ... @@ -29,13 +29,11 @@ export default function QuestionBankModal() {
29 29 draftPagination;
30 30 const [form] = Form.useForm();
31 31 const [confirmLoading, setComfirmLoading] = useState(false);
32   - const [standardId, setStandardId] = useState<number>();
33 32  
34 33 useEffect(() => {
35 34 if (visible) {
36 35 currentItem && form.setFieldsValue(currentItem);
37 36 if (currentItem) {
38   - setStandardId(currentItem.standardId);
39 37 form.setFieldsValue({
40 38 name: currentItem.name,
41 39 standardId: currentItem.standardId,
... ... @@ -46,6 +44,13 @@ export default function QuestionBankModal() {
46 44 value: role.roleCode,
47 45 })),
48 46 },
  47 + adapter: {
  48 + type: currentItem.adapterType,
  49 + list: currentItem.adapterList?.map((range) => ({
  50 + value: range.adapterId,
  51 + label: range.adapterName,
  52 + })),
  53 + },
49 54 });
50 55 } else {
51 56 form.setFieldsValue({
... ... @@ -68,6 +73,11 @@ export default function QuestionBankModal() {
68 73 roleCode: item.value,
69 74 roleName: item.label,
70 75 })),
  76 + adapterType: val?.adapter?.type,
  77 + adapterList: val?.adapter?.list?.map((item: any) => ({
  78 + adapterId: item.value,
  79 + adapterName: item.label,
  80 + })),
71 81 };
72 82 const api = TYPE === 2 || isDraft ? saveDraftApi : saveQuestionBankApi;
73 83 api(params)
... ... @@ -88,13 +98,6 @@ export default function QuestionBankModal() {
88 98 });
89 99 };
90 100  
91   - const standardChange = (standard: LabeledValue) => {
92   - if (!!standard && visible) {
93   - setStandardId(+standard?.value);
94   - }
95   - return standard;
96   - };
97   -
98 101 const validatorRole = (rule: any, value: any) => {
99 102 if (!value) return Promise.reject(Error("请选择适用角色"));
100 103 if (value.type === 2 && !value?.list) {
... ... @@ -103,6 +106,32 @@ export default function QuestionBankModal() {
103 106 return Promise.resolve();
104 107 };
105 108  
  109 + const validatorBrandOrSeries = (
  110 + rule: any,
  111 + value: any = { type: 1, list: [] }
  112 + ) => {
  113 + if (value.type === 4) return Promise.resolve();
  114 + if (!value.type || !value.list?.length) {
  115 + return Promise.reject(Error("请选择适用范围"));
  116 + }
  117 + if (value.list && value.list.length > 0) return Promise.resolve();
  118 + else {
  119 + return Promise.reject(
  120 + Error(
  121 + `请选择${
  122 + value.type === 1
  123 + ? "品牌"
  124 + : value.type === 2
  125 + ? "车系"
  126 + : value.type === 3
  127 + ? "门店"
  128 + : "适用范围"
  129 + }`
  130 + )
  131 + );
  132 + }
  133 + };
  134 +
106 135 return (
107 136 <Modal
108 137 title={
... ... @@ -144,7 +173,6 @@ export default function QuestionBankModal() {
144 173 name="standardId"
145 174 label="业务类型"
146 175 rules={[{ required: true, message: "请选择业务类型" }]}
147   - getValueFromEvent={standardChange}
148 176 >
149 177 <TreeSelect
150 178 allowClear
... ... @@ -164,6 +192,19 @@ export default function QuestionBankModal() {
164 192 />
165 193 </Form.Item>
166 194 <Form.Item
  195 + label="适用范围"
  196 + name="adapter"
  197 + rules={[
  198 + {
  199 + required: true,
  200 + validator: validatorBrandOrSeries,
  201 + message: "请选择适用范围",
  202 + },
  203 + ]}
  204 + >
  205 + <SelectBrandOrSeries mode="multiple" />
  206 + </Form.Item>
  207 + <Form.Item
167 208 name="role"
168 209 label="适用角色"
169 210 required
... ...
src/pages/ehr/ProgramOfStudy/QuestionBank/components/QuestionBankList/components/ApprovalProgressModal.tsx 0 → 100644
  1 +/*
  2 + * @Author: wangqiang@feewee.cn
  3 + * @Date: 2022-10-26 09:24:59
  4 + * @LastEditors: wangqiang@feewee.cn
  5 + * @LastEditTime: 2023-02-09 17:43:55
  6 + */
  7 +import ApprovalProgress from "@/components/ApprovalProgress";
  8 +import { Button, Modal } from "antd";
  9 +import React from "react";
  10 +import { useStore } from "../../../index";
  11 +
  12 +export default function ApprovalProgressModal() {
  13 + const { approvalProgressModalInfo, setApprovalProgressModalInfo } =
  14 + useStore();
  15 +
  16 + const onCancel = () => setApprovalProgressModalInfo({ visible: false });
  17 +
  18 + return (
  19 + <Modal
  20 + title={`${
  21 + approvalProgressModalInfo.title
  22 + ? approvalProgressModalInfo.title + "-"
  23 + : ""
  24 + }审批进度`}
  25 + open={approvalProgressModalInfo.visible}
  26 + onCancel={onCancel}
  27 + maskClosable={false}
  28 + destroyOnClose
  29 + footer={[
  30 + <Button key="cancel" onClick={onCancel}>
  31 + 关闭
  32 + </Button>,
  33 + ]}
  34 + >
  35 + <ApprovalProgress orderNo={approvalProgressModalInfo.orderNo} />
  36 + </Modal>
  37 + );
  38 +}
... ...
src/pages/ehr/ProgramOfStudy/QuestionBank/components/QuestionBankList/components/DraftList/index.tsx
1 1 /*
2 2 * @Date: 2021-07-26 17:19:45
3 3 * @LastEditors: wangqiang@feewee.cn
4   - * @LastEditTime: 2022-11-21 20:01:42
  4 + * @LastEditTime: 2023-02-09 17:54:02
5 5 */
6 6 import React, { useEffect } from "react";
7 7 import { useStore } from "../../../../index";
... ... @@ -20,6 +20,8 @@ import {
20 20 import { PlusOutlined } from "@ant-design/icons";
21 21 import { debounce } from "lodash";
22 22 import QuestionBankModal from "../../QuestionBankModal";
  23 +import { AdapterType } from "@/pages/ehr/ProgramOfStudy/Settings/store";
  24 +import ApprovalProgressModal from "@/pages/ehr/ProgramOfStudy/QuestionBank/components/QuestionBankList/components/ApprovalProgressModal";
23 25  
24 26 enum Status {
25 27 "default" = 1,
... ... @@ -44,10 +46,11 @@ export default function DraftList() {
44 46 breadcrumbs,
45 47 setBreadcrumbs,
46 48 setCurrentBreadcrumb,
47   - roleVisible,
48   - setRoleVisible,
  49 + detailModalInfo,
  50 + setDetailModalInfo,
49 51 isDraft,
50 52 setIsDraft,
  53 + setApprovalProgressModalInfo,
51 54 } = useStore();
52 55 const {
53 56 list,
... ... @@ -57,7 +60,6 @@ export default function DraftList() {
57 60 setParams,
58 61 paginationConfig,
59 62 } = draftPagination;
60   - const { current, pageSize } = paginationConfig;
61 63  
62 64 useEffect(() => {
63 65 if (isDraft) {
... ... @@ -81,21 +83,31 @@ export default function DraftList() {
81 83 };
82 84  
83 85 const delBank = (id: number) => {
  86 + const hide = message.loading("删除中,请稍后...", 0);
84 87 deleteDraftApi(id)
85 88 .then((res) => {
  89 + hide();
86 90 message.success(res.result);
87 91 setLoading(true);
88 92 })
89   - .catch((error) => message.error(error.message));
  93 + .catch((error) => {
  94 + hide();
  95 + message.error(error.message);
  96 + });
90 97 };
91 98  
92 99 const approvalDraft = (draftId: number) => {
  100 + const hide = message.loading("提交中,请稍后...", 0);
93 101 approvalDraftApi(draftId)
94 102 .then((res) => {
  103 + hide();
95 104 message.success(res.result);
96 105 setLoading(true);
97 106 })
98   - .catch((error) => message.error(error.message));
  107 + .catch((error) => {
  108 + hide();
  109 + message.error(error.message);
  110 + });
99 111 };
100 112  
101 113 const search = debounce(
... ... @@ -132,12 +144,6 @@ export default function DraftList() {
132 144 loading={loading}
133 145 >
134 146 <Table.Column
135   - title="题库编号"
136   - dataIndex="id"
137   - align="left"
138   - render={(id: number, record: QuestionBank.List, index: number) => index + 1 + (current! - 1) * pageSize!}
139   - />
140   - <Table.Column
141 147 title="题库名称"
142 148 dataIndex="name"
143 149 align="left"
... ... @@ -161,26 +167,44 @@ export default function DraftList() {
161 167 <Table.Column
162 168 title="适用角色"
163 169 align="left"
164   - render={(record: QuestionBank.List) => (
165   - <span
166   - style={{ color: record.scopeType === 1 ? "orange" : "purple" }}
167   - >
168   - {record.scopeType === 1 ? (
169   - "全部"
170   - ) : record.roleList?.length ? (
  170 + render={(record: QuestionBank.List) => (record.scopeType === 1 ? (
  171 + "全部角色"
  172 + ) : record.roleList?.length ? (
  173 + <a
  174 + onClick={() => {
  175 + setCurrentItem(record);
  176 + setDetailModalInfo({ visible: true, type: "适用角色" });
  177 + }}
  178 + >
  179 + 部分角色
  180 + </a>
  181 + ) : (
  182 + "-"
  183 + ))}
  184 + />
  185 + <Table.Column
  186 + title="适用范围"
  187 + align="left"
  188 + render={(record: QuestionBank.List) => (record.adapterType ? (
  189 + record.adapterType === AdapterType.全部门店 ? (
  190 + "全部门店"
  191 + ) : (
171 192 <a
172 193 onClick={() => {
173 194 setCurrentItem(record);
174   - setRoleVisible(true);
  195 + setDetailModalInfo({
  196 + visible: true,
  197 + type: "适用范围",
  198 + typeName: AdapterType[record.adapterType!],
  199 + });
175 200 }}
176 201 >
177   - 部分
  202 + {AdapterType[record.adapterType]}
178 203 </a>
179   - ) : (
180   - "-"
181   - )}
182   - </span>
183   - )}
  204 + )
  205 + ) : (
  206 + "-"
  207 + ))}
184 208 />
185 209 <Table.Column
186 210 title="状态"
... ... @@ -193,56 +217,90 @@ export default function DraftList() {
193 217 <Table.Column
194 218 title="操作"
195 219 align="left"
196   - render={(record: QuestionBank.List) => (record.status === StatusText["审批中"] ? (
197   - <span style={{ color: "#999" }}>审批中的草稿无法操作</span>
198   - ) : (
199   - <>
200   - <a
201   - onClick={() => {
202   - setCurrentItem(record);
203   - setVisible(true);
204   - }}
205   - >
206   - 编辑
207   - </a>
208   - <Divider type="vertical" />
209   - <Popconfirm
210   - title={`确定提交【${record.name}】审批?`}
211   - onConfirm={() => approvalDraft(record.id!)}
212   - >
213   - <a style={{ color: "#faad14" }}>提交审批</a>
214   - </Popconfirm>
215   - <Divider type="vertical" />
216   - <Popconfirm
217   - title={`确定删除【${record.name}】?`}
218   - onConfirm={() => delBank(record.id!)}
219   - >
220   - <a style={{ color: "red" }}>删除</a>
221   - </Popconfirm>
222   - </>
223   - ))}
  220 + render={(record: QuestionBank.List) => (
  221 + <>
  222 + {record.auditNo ? (
  223 + <>
  224 + <a
  225 + onClick={() => {
  226 + setApprovalProgressModalInfo({
  227 + title: record.name,
  228 + visible: true,
  229 + orderNo: record.auditNo,
  230 + });
  231 + }}
  232 + >
  233 + 审批进度
  234 + </a>
  235 + <Divider type="vertical" />
  236 + </>
  237 + ) : null}
  238 + {record.status === StatusText.审批中 ? null : (
  239 + <>
  240 + <a
  241 + onClick={() => {
  242 + setCurrentItem(record);
  243 + setVisible(true);
  244 + }}
  245 + >
  246 + 编辑
  247 + </a>
  248 + <Divider type="vertical" />
  249 + <Popconfirm
  250 + title={`确定提交【${record.name}】审批?`}
  251 + onConfirm={() => approvalDraft(record.id!)}
  252 + >
  253 + <a style={{ color: "#faad14" }}>提交审批</a>
  254 + </Popconfirm>
  255 + <Divider type="vertical" />
  256 + <Popconfirm
  257 + title={`确定删除【${record.name}】?`}
  258 + onConfirm={() => delBank(record.id!)}
  259 + >
  260 + <a style={{ color: "red" }}>删除</a>
  261 + </Popconfirm>
  262 + </>
  263 + )}
  264 + </>
  265 + )}
224 266 />
225 267 </Table>
226 268 <QuestionBankModal />
227 269 <Modal
228   - title={currentItem && `【${currentItem.name}】适用角色`}
229   - visible={roleVisible}
  270 + title={
  271 + currentItem &&
  272 + `【${currentItem.name}】-${detailModalInfo.type}${
  273 + detailModalInfo.typeName ? `-${detailModalInfo.typeName}` : ""
  274 + }`
  275 + }
  276 + visible={detailModalInfo.visible}
230 277 maskClosable={false}
231   - onOk={() => setRoleVisible(false)}
232   - onCancel={() => setRoleVisible(false)}
  278 + onOk={() => setDetailModalInfo({ visible: false, type: "适用角色" })}
  279 + onCancel={() => setDetailModalInfo({ visible: false, type: "适用角色" })}
233 280 footer={[
234   - <Button key="1" onClick={() => setRoleVisible(false)}>
  281 + <Button
  282 + key="1"
  283 + onClick={() => setDetailModalInfo({ visible: false, type: "适用角色" })}
  284 + >
235 285 关闭
236 286 </Button>,
237 287 ]}
238 288 afterClose={() => setCurrentItem(undefined)}
239 289 >
240 290 <div style={{ flex: 1, maxHeight: 550, overflowY: "auto" }}>
241   - {currentItem?.roleList?.map((role, index) => (
242   - <p key={role.roleCode}>{role.roleName}</p>
243   - ))}
  291 + {detailModalInfo.type === "适用角色"
  292 + ? currentItem?.roleList?.map((role, index) => (
  293 + <p key={role.roleCode}>{role.roleName}</p>
  294 + ))
  295 + : null}
  296 + {detailModalInfo.type === "适用范围"
  297 + ? currentItem?.adapterList?.map((adapter, index) => (
  298 + <p key={adapter.adapterId}>{adapter.adapterName}</p>
  299 + ))
  300 + : null}
244 301 </div>
245 302 </Modal>
  303 + <ApprovalProgressModal />
246 304 </>
247 305 );
248 306 }
... ...
src/pages/ehr/ProgramOfStudy/QuestionBank/components/QuestionBankList/components/UsingList/index.tsx
1 1 /*
2 2 * @Date: 2021-07-26 17:19:45
3 3 * @LastEditors: wangqiang@feewee.cn
4   - * @LastEditTime: 2022-12-09 19:07:33
  4 + * @LastEditTime: 2023-02-09 17:52:44
5 5 */
6 6 import React, { useEffect, useState } from "react";
7 7 import { useStore } from "../../../../index";
... ... @@ -21,6 +21,8 @@ import { debounce } from &quot;lodash&quot;;
21 21 import QuestionBankModal from "../../QuestionBankModal";
22 22 import RangeRoleSelector from "@/pages/ehr/ProgramOfStudy/components/RangeRoleSelector";
23 23 import FeeweeFilterOption from "@/pages/notice/components/FeeweeFilterOption";
  24 +import SelectBrandOrSeries from "@/pages/ehr/ProgramOfStudy/components/SelectBrandOrSeries";
  25 +import { AdapterType } from "@/pages/ehr/ProgramOfStudy/Settings/store";
24 26  
25 27 export default function UsingList() {
26 28 const {
... ... @@ -32,8 +34,8 @@ export default function UsingList() {
32 34 breadcrumbs,
33 35 setBreadcrumbs,
34 36 setCurrentBreadcrumb,
35   - roleVisible,
36   - setRoleVisible,
  37 + detailModalInfo,
  38 + setDetailModalInfo,
37 39 setIsDraft,
38 40 setTYPE,
39 41 draftPagination,
... ... @@ -47,7 +49,6 @@ export default function UsingList() {
47 49 setParams,
48 50 paginationConfig,
49 51 } = pagination;
50   - const { current, pageSize } = paginationConfig;
51 52 const [getDraftLoading, setGetDraftLoading] = useState(false);
52 53  
53 54 useEffect(() => {
... ... @@ -62,12 +63,17 @@ export default function UsingList() {
62 63 };
63 64  
64 65 const delBank = (id: number) => {
  66 + const hide = message.loading("删除中,请稍后...", 0);
65 67 deleteQuestionBankApi(id)
66 68 .then((res) => {
  69 + hide();
67 70 message.success("删除成功");
68 71 setLoading(true);
69 72 })
70   - .catch((error) => message.error(error.message));
  73 + .catch((error) => {
  74 + hide();
  75 + message.error(error.message);
  76 + });
71 77 };
72 78  
73 79 const search = debounce(
... ... @@ -162,6 +168,32 @@ export default function UsingList() {
162 168 display: innerParams.standardId ? "flex" : "none",
163 169 }}
164 170 />
  171 + <SelectBrandOrSeries
  172 + useFilter
  173 + value={{
  174 + type: pagination.innerParams.adapterType,
  175 + list:
  176 + pagination.innerParams.adapterId &&
  177 + pagination.innerParams.adapterName
  178 + ? [
  179 + {
  180 + value: pagination.innerParams.adapterId,
  181 + label: pagination.innerParams.adapterName,
  182 + },
  183 + ]
  184 + : undefined,
  185 + }}
  186 + onChange={(value: any) => {
  187 + pagination.setParams(
  188 + {
  189 + adapterType: value?.type,
  190 + adapterId: value?.list?.[0]?.value,
  191 + adapterName: value?.list?.[0]?.label,
  192 + },
  193 + true
  194 + );
  195 + }}
  196 + />
165 197 {/* </Row> */}
166 198 {/* <Button icon={(<PlusOutlined />)} type="primary" onClick={() => { setCurrentItem(undefined); setVisible(true); }}>添加题库</Button> */}
167 199 </Row>
... ... @@ -172,12 +204,6 @@ export default function UsingList() {
172 204 loading={loading || getDraftLoading}
173 205 >
174 206 <Table.Column
175   - title="题库编号"
176   - dataIndex="id"
177   - align="left"
178   - render={(id: number, record: QuestionBank.List, index: number) => index + 1 + (current! - 1) * pageSize!}
179   - />
180   - <Table.Column
181 207 title="题库名称"
182 208 dataIndex="name"
183 209 align="left"
... ... @@ -197,26 +223,44 @@ export default function UsingList() {
197 223 <Table.Column
198 224 title="适用角色"
199 225 align="left"
200   - render={(record: QuestionBank.List) => (
201   - <span
202   - style={{ color: record.scopeType === 1 ? "orange" : "purple" }}
203   - >
204   - {record.scopeType === 1 ? (
205   - "全部角色"
206   - ) : record.roleList?.length ? (
  226 + render={(record: QuestionBank.List) => (record.scopeType === 1 ? (
  227 + "全部角色"
  228 + ) : record.roleList?.length ? (
  229 + <a
  230 + onClick={() => {
  231 + setCurrentItem(record);
  232 + setDetailModalInfo({ visible: true, type: "适用角色" });
  233 + }}
  234 + >
  235 + 部分角色
  236 + </a>
  237 + ) : (
  238 + "-"
  239 + ))}
  240 + />
  241 + <Table.Column
  242 + title="适用范围"
  243 + align="left"
  244 + render={(record: QuestionBank.List) => (record.adapterType ? (
  245 + record.adapterType === AdapterType.全部门店 ? (
  246 + "全部门店"
  247 + ) : (
207 248 <a
208 249 onClick={() => {
209 250 setCurrentItem(record);
210   - setRoleVisible(true);
  251 + setDetailModalInfo({
  252 + visible: true,
  253 + type: "适用范围",
  254 + typeName: AdapterType[record.adapterType!],
  255 + });
211 256 }}
212 257 >
213   - 部分角色
  258 + {AdapterType[record.adapterType]}
214 259 </a>
215   - ) : (
216   - "-"
217   - )}
218   - </span>
219   - )}
  260 + )
  261 + ) : (
  262 + "-"
  263 + ))}
220 264 />
221 265 <Table.Column
222 266 title="操作"
... ... @@ -251,22 +295,37 @@ export default function UsingList() {
251 295 </Table>
252 296 <QuestionBankModal />
253 297 <Modal
254   - title={currentItem && `【${currentItem.name}】适用角色`}
255   - visible={roleVisible}
  298 + title={
  299 + currentItem &&
  300 + `【${currentItem.name}】-${detailModalInfo.type}${
  301 + detailModalInfo.typeName ? `-${detailModalInfo.typeName}` : ""
  302 + }`
  303 + }
  304 + visible={detailModalInfo.visible}
256 305 maskClosable={false}
257   - onOk={() => setRoleVisible(false)}
258   - onCancel={() => setRoleVisible(false)}
  306 + onOk={() => setDetailModalInfo({ visible: false, type: "适用角色" })}
  307 + onCancel={() => setDetailModalInfo({ visible: false, type: "适用角色" })}
259 308 footer={[
260   - <Button key="1" onClick={() => setRoleVisible(false)}>
  309 + <Button
  310 + key="1"
  311 + onClick={() => setDetailModalInfo({ visible: false, type: "适用角色" })}
  312 + >
261 313 关闭
262 314 </Button>,
263 315 ]}
264 316 afterClose={() => setCurrentItem(undefined)}
265 317 >
266 318 <div style={{ flex: 1, maxHeight: 550, overflowY: "auto" }}>
267   - {currentItem?.roleList?.map((role, index) => (
268   - <p key={role.roleCode}>{role.roleName}</p>
269   - ))}
  319 + {detailModalInfo.type === "适用角色"
  320 + ? currentItem?.roleList?.map((role, index) => (
  321 + <p key={role.roleCode}>{role.roleName}</p>
  322 + ))
  323 + : null}
  324 + {detailModalInfo.type === "适用范围"
  325 + ? currentItem?.adapterList?.map((adapter, index) => (
  326 + <p key={adapter.adapterId}>{adapter.adapterName}</p>
  327 + ))
  328 + : null}
270 329 </div>
271 330 </Modal>
272 331 </>
... ...
src/pages/ehr/ProgramOfStudy/QuestionBank/index.tsx
1 1 /*
2 2 * @Date: 2021-07-14 10:54:47
3 3 * @LastEditors: wangqiang@feewee.cn
4   - * @LastEditTime: 2021-07-27 17:08:02
  4 + * @LastEditTime: 2023-02-09 17:00:20
5 5 */
6   -import React, { useEffect, useState } from 'react';
7   -import { Card, ConfigProvider, Breadcrumb } from 'antd';
8   -import zhCN from 'antd/lib/locale-provider/zh_CN';
9   -import { PageHeaderWrapper } from '@ant-design/pro-layout';
10   -import List from './components/QuestionBankList';
11   -import Item from './components/QuestionBankItem';
12   -import { createStore } from '@/hooks/moz';
13   -import store, { BreadcrumbItem } from './store';
14   -import './style.less';
  6 +import React, { useEffect, useState } from "react";
  7 +import { Card, ConfigProvider, Breadcrumb } from "antd";
  8 +import zhCN from "antd/lib/locale-provider/zh_CN";
  9 +import { PageHeaderWrapper } from "@ant-design/pro-layout";
  10 +import List from "./components/QuestionBankList";
  11 +import Item from "./components/QuestionBankItem";
  12 +import { createStore } from "@/hooks/moz";
  13 +import store, { BreadcrumbItem } from "./store";
  14 +import "./style.less";
15 15  
16 16 export const { Provider, useStore } = createStore(store);
17 17  
... ... @@ -25,17 +25,17 @@ function QuestionBank() {
25 25 setCurrentBreadcrumb,
26 26 currentItem,
27 27 setCurrentItem,
28   - TYPE
  28 + TYPE,
29 29 } = useStore();
30 30 const { setLoading } = pagination;
31 31 const [IndexDOM, setIndexDOM] = useState(<List />);
32 32  
33 33 useEffect(() => {
34 34 switch (currentBreadcrumb.key) {
35   - case 'list':
  35 + case "list":
36 36 setIndexDOM(<List />);
37 37 break;
38   - case 'detail':
  38 + case "detail":
39 39 setIndexDOM(<Item />);
40 40 break;
41 41 default:
... ... @@ -45,32 +45,51 @@ function QuestionBank() {
45 45  
46 46 const breadcrumbClick = (breadcrumb: BreadcrumbItem, index: number) => {
47 47 if (breadcrumb.key === currentBreadcrumb.key) return;
48   - if (breadcrumb.key === 'list') {
  48 + if (breadcrumb.key === "list") {
49 49 setCurrentItem(undefined);
50 50 setLoading(true);
51 51 setFactoryId(0);
52 52 }
53 53 setCurrentBreadcrumb(breadcrumb);
54 54 setBreadcrumbs(breadcrumbs.slice(0, index + 1));
55   - }
  55 + };
56 56  
57 57 return (
58   - <PageHeaderWrapper title={(
59   - <div>
60   - <span>题库设置{currentBreadcrumb.key === 'detail' ? `-${currentItem ? `编辑${TYPE === 2 ? '草稿' : ''}(${currentItem.name})` : `添加${TYPE === 2 ? '草稿' : ''}`}` : null}</span>
61   - <Breadcrumb separator='>' style={{ marginTop: 10 }}>
62   - {breadcrumbs.map((breadcrumb, index) =>
63   - <Breadcrumb.Item onClick={() => breadcrumbClick(breadcrumb, index)} key={breadcrumb.key}><a>{breadcrumb.name}</a></Breadcrumb.Item>)}
64   - </Breadcrumb>
65   - </div>
66   - )}>
  58 + <PageHeaderWrapper
  59 + title={
  60 + <div>
  61 + <span>
  62 + 题库设置
  63 + {currentBreadcrumb.key === "detail"
  64 + ? `-${
  65 + currentItem
  66 + ? `编辑${TYPE === 2 ? "草稿" : ""}(${currentItem.name})`
  67 + : `添加${TYPE === 2 ? "草稿" : ""}`
  68 + }`
  69 + : null}
  70 + </span>
  71 + <Breadcrumb separator=">" style={{ marginTop: 10 }}>
  72 + {breadcrumbs.map((breadcrumb, index) => (
  73 + <Breadcrumb.Item
  74 + onClick={() => breadcrumbClick(breadcrumb, index)}
  75 + key={breadcrumb.key}
  76 + >
  77 + <a>{breadcrumb.name}</a>
  78 + </Breadcrumb.Item>
  79 + ))}
  80 + </Breadcrumb>
  81 + </div>
  82 + }
  83 + >
67 84 <ConfigProvider locale={zhCN}>
68   - <Card bordered={false}>
69   - {IndexDOM}
70   - </Card>
  85 + <Card bordered={false}>{IndexDOM}</Card>
71 86 </ConfigProvider>
72 87 </PageHeaderWrapper>
73   - )
  88 + );
74 89 }
75 90  
76   -export default () => <Provider><QuestionBank /></Provider>
  91 +export default () => (
  92 + <Provider>
  93 + <QuestionBank />
  94 + </Provider>
  95 +);
... ...
src/pages/ehr/ProgramOfStudy/QuestionBank/interface.d.ts
1 1 /*
2 2 * @Date: 2021-02-24 09:57:33
3 3 * @LastEditors: wangqiang@feewee.cn
4   - * @LastEditTime: 2022-11-21 19:50:00
  4 + * @LastEditTime: 2023-02-09 17:42:00
5 5 */
6 6 declare namespace QuestionBank {
7 7 interface QueryParams {
... ... @@ -10,6 +10,9 @@ declare namespace QuestionBank {
10 10 standardId?: number; // 业务类型ID
11 11 scopeType?: number; // 适配范围 1通用 2部分
12 12 roleCode?: string; // 角色码
  13 + adapterType?: number; // 适配类型 1品牌 2车系 3门店 4通用
  14 + adapterId?: number;
  15 + adapterName?: string;
13 16 }
14 17  
15 18 interface List {
... ... @@ -21,7 +24,15 @@ declare namespace QuestionBank {
21 24 roleList?: RoleVO[];
22 25 standardId?: number; //业务类型ID
23 26 standardName?: string; //业务类型名称
  27 + adapterType?: number; // 适配类型 1品牌 2车系 3门店 4通用
  28 + adapterList?: AdapterVO[]; // 适配列表
24 29 status?: 1 | 2; //状态 1草稿 2审批中 3审批拒绝
  30 + auditNo?: string; // 审批编号
  31 + }
  32 +
  33 + interface AdapterVO {
  34 + adapterId?: number;
  35 + adapterName?: string;
25 36 }
26 37  
27 38 interface RoleVO {
... ...
src/pages/ehr/ProgramOfStudy/QuestionBank/store.ts
1 1 /*
2 2 * @Date: 2021-02-24 09:57:33
3 3 * @LastEditors: wangqiang@feewee.cn
4   - * @LastEditTime: 2022-12-09 17:50:05
  4 + * @LastEditTime: 2023-02-09 17:50:44
5 5 */
6 6 import useInitial from "@/hooks/useInitail";
7 7 import usePagination from "@/hooks/usePagination";
8   -import { getUserAbilityTypeListApi } from '@/pages/ehr/ProgramOfStudy/api';
  8 +import { getUserAbilityTypeListApi } from "@/pages/ehr/ProgramOfStudy/api";
9 9 import { useState, ReactNode } from "react";
10 10 import {
11 11 getQuestionBankListApi,
... ... @@ -68,11 +68,7 @@ export default function useStore() {
68 68 const [isAddFinish, setIsAddFinish] = useState(true);
69 69 const [currentItem, setCurrentItem] = useState<QuestionBank.List>();
70 70 // 列表项
71   - const pagination = usePagination<QuestionBank.List[]>(
72   - getQuestionBankListApi,
73   - {},
74   - {}
75   - );
  71 + const pagination = usePagination(getQuestionBankListApi, {});
76 72 const [delay, setQuestionDelay] = useState(true);
77 73 const [factoryId, setFactoryId] = useState(0);
78 74 const [draftId, setDraftId] = useState(0);
... ... @@ -86,7 +82,11 @@ export default function useStore() {
86 82 { node: ReactNode; index: number }[]
87 83 >([]);
88 84 const [abilityAttachVisible, setAbilityAttachVisible] = useState(false);
89   - const [roleVisible, setRoleVisible] = useState(false);
  85 + const [detailModalInfo, setDetailModalInfo] = useState<{
  86 + visible: boolean;
  87 + type: "适用角色" | "适用范围";
  88 + typeName?: string;
  89 + }>({ visible: false, type: "适用角色" });
90 90  
91 91 const draftPagination = usePagination(getDraftListApi);
92 92 const draftQuestionInitial = useInitial(
... ... @@ -104,6 +104,8 @@ export default function useStore() {
104 104 [],
105 105 undefined
106 106 );
  107 + const [approvalProgressModalInfo, setApprovalProgressModalInfo] =
  108 + useState<PublicNotice.ApprovalProgressModalInfo>({ visible: false });
107 109  
108 110 // useEffect(() => {
109 111 // if (factoryId > 0) {
... ... @@ -145,8 +147,8 @@ export default function useStore() {
145 147 setAddModalContents,
146 148 abilityAttachVisible,
147 149 setAbilityAttachVisible,
148   - roleVisible,
149   - setRoleVisible,
  150 + detailModalInfo,
  151 + setDetailModalInfo,
150 152 draftPagination,
151 153 draftQuestionInitial,
152 154 isBatchDelete,
... ... @@ -156,5 +158,7 @@ export default function useStore() {
156 158 isDraft,
157 159 setIsDraft,
158 160 abilityTypeInitial,
  161 + approvalProgressModalInfo,
  162 + setApprovalProgressModalInfo,
159 163 };
160 164 }
... ...
src/pages/ehr/ProgramOfStudy/Settings/components/ApprovalProgressModal.tsx
... ... @@ -2,7 +2,7 @@
2 2 * @Author: wangqiang@feewee.cn
3 3 * @Date: 2022-10-26 09:24:59
4 4 * @LastEditors: wangqiang@feewee.cn
5   - * @LastEditTime: 2022-10-26 17:56:29
  5 + * @LastEditTime: 2023-02-09 17:43:52
6 6 */
7 7 import ApprovalProgress from "@/components/ApprovalProgress";
8 8 import { Button, Modal } from "antd";
... ... @@ -25,6 +25,7 @@ export default function ApprovalProgressModal() {
25 25 open={approvalProgressModalInfo.visible}
26 26 onCancel={onCancel}
27 27 maskClosable={false}
  28 + destroyOnClose
28 29 footer={[
29 30 <Button key="cancel" onClick={onCancel}>
30 31 关闭
... ...