Commit ed0769d7a36d433bba65d70b4849ce21cdb12941

Authored by 王强
2 parents 26e57c4d 1128146a

Merge remote-tracking branch 'origin/bug_fix' into ehr-manage

Showing 32 changed files with 1711 additions and 127 deletions
build/admin.tar.gz
No preview for this file type
config/routers/backlog.ts
1 1 export default [
2 2 {
3   - path: "./backlog/taskConfig", // 待办配置
  3 + path: "/backlog/taskConfig", // 待办配置
4 4 component: "./backlog/TaskConfig",
5 5 },
6 6 {
7   - path: "./backlog/taskTime", // 待办时效
  7 + path: "/backlog/taskTime", // 待办时效
8 8 component: "./backlog/TaskTime",
9 9 },
10 10 /**工作类型配置 */
11 11 {
12   - path: "./backlog/workConfig",
  12 + path: "/backlog/workConfig",
13 13 component: "./backlog/WorkTypeConfig",
14 14 },
  15 + {
  16 + path: "/backlog/intervention/over", // 超时待办干预
  17 + component: "./backlog/OverIntervention",
  18 + },
  19 + {
  20 + path: "/backlog/intervention/setting", // 异常干预配置
  21 + component: "./backlog/InterventionSetting",
  22 + },
  23 + {
  24 + path: "/backlog/intervention/info", // 异常干预
  25 + component: "./backlog/Intervention",
  26 + },
15 27 ];
... ...
src/pages/admin/Privilege/api.ts
... ... @@ -5,9 +5,7 @@ import { HOST } from "@/utils/host";
5 5 type P<T> = http.PromiseResp<T>;
6 6  
7 7 // 获取系统列表
8   -export function systemListApi(
9   - params?: Privilege.SystemListParams
10   -): http.PromisePageResp<Privilege.SystemListVO> {
  8 +export function systemListApi(params?: Privilege.SystemListParams): http.PromisePageResp<Privilege.SystemListVO> {
11 9 return request.get(`${HOST}/system/list`, { params });
12 10 }
13 11  
... ... @@ -55,9 +53,7 @@ export function deleteSystem(sysId: number): http.PromiseResp&lt;any&gt; {
55 53 }
56 54  
57 55 /** 获取资源 */
58   -export function priviListApi(
59   - params: Privilege.PrivilegeListParams
60   -): http.PromiseRespA<Privilege.PrivilegeData> {
  56 +export function priviListApi(params: Privilege.PrivilegeListParams): http.PromiseRespA<Privilege.PrivilegeData> {
61 57 return request.get(`${HOST}/privilege/list`, { params });
62 58 }
63 59  
... ... @@ -140,8 +136,8 @@ export function PrivilegePerson(id: number): P&lt;Item[]&gt; {
140 136 * @description: 查询所有角色,用于给资源菜单授权当做数据源
141 137 * @return {P<Item[]>}
142 138 */
143   -export function getAllRoleListApi(): P<Item[]> {
144   - return request.get(`${HOST}/common/role/all`);
  139 +export function getAllRoleListApi(params?: object): P<Item[]> {
  140 + return request.get(`${HOST}/common/role/all`, { params });
145 141 }
146 142  
147 143 export interface RoleAuthParams {
... ...
src/pages/backlog/Intervention/api.ts 0 → 100644
  1 +import request from "@/utils/request";
  2 +import { BACKLOG } from "@/utils/host";
  3 +import { http } from "@/typing/http";
  4 +import { PaginationParam } from "@/typing/common";
  5 +
  6 +export interface ListVO {
  7 + id: number;
  8 + /** 干预事项编码 */
  9 + code?: string;
  10 + /** 干预事项名称 */
  11 + name?: string;
  12 + /** 待办配置id */
  13 + configId?: number;
  14 + /** 待办名称 */
  15 + itemName?: string;
  16 + /** 系统id */
  17 + applySysId?: number;
  18 + /** 系统名称 */
  19 + applySysName?: string;
  20 + /** 干预事项id */
  21 + interveneId?: number;
  22 +}
  23 +
  24 +export interface Params extends PaginationParam {
  25 + sysId?: number;
  26 + configId?: number;
  27 + /** 角色编码 */
  28 + roleCode?: string;
  29 + keywords?: string;
  30 +}
  31 +
  32 +export function queryPageList(params?: Params): http.PromisePageResp<ListVO> {
  33 + return request.get(`${BACKLOG}/meddle/list`, { params });
  34 +}
  35 +
  36 +export interface SaveParams {
  37 + id?: number;
  38 + /** interveneId */
  39 + interveneId?: number;
  40 + interveneList?: Item[];
  41 +}
  42 +
  43 +export interface Item {
  44 + /** 触发阀值 */
  45 + threshold: number;
  46 + /** 角色编码 */
  47 + roleCode: string;
  48 + /** 角色名称 */
  49 + roleName: string;
  50 +}
  51 +
  52 +export function save(params: SaveParams): http.PromiseResp<void> {
  53 + return request.post(`${BACKLOG}/meddle/save`, { ...params });
  54 +}
  55 +
  56 +export interface InterveneVO {
  57 + id: number;
  58 + code: string;
  59 + name: string;
  60 + valueDesc: string;
  61 + valueUnit: string;
  62 +}
  63 +
  64 +export function queryInterveneSettingList(params: { interveneId?: number }): http.PromiseRespA<InterveneVO> {
  65 + return request.get(`${BACKLOG}/intervene/auth/list`, { params });
  66 +}
  67 +
  68 +export interface BacklogItemVO {
  69 + id: number;
  70 + itemCode: string;
  71 + itemName: string;
  72 +}
  73 +
  74 +export function queryBacklogList(): http.PromiseRespA<BacklogItemVO> {
  75 + return request.get(`${BACKLOG}/config/over/list`);
  76 +}
  77 +
  78 +export function queryThresholds(params: any): http.PromiseRespA<Item> {
  79 + return request.get(`${BACKLOG}/meddle/notify/thresholds`, { params });
  80 +}
  81 +
  82 +export function deleteData(id?: number): http.PromiseResp<void> {
  83 + return request.get(`${BACKLOG}/meddle/delete`, { params: { id } });
  84 +}
... ...
src/pages/backlog/Intervention/components/EditModal.tsx 0 → 100644
  1 +import React, { useEffect, useState } from "react";
  2 +import { Modal, Form, Select, message, Skeleton } from "antd";
  3 +import { save, ListVO, queryThresholds, InterveneVO, queryInterveneSettingList } from "../api";
  4 +import SettingList from "./SettingList";
  5 +
  6 +interface Props {
  7 + visible: boolean;
  8 + onCancel: () => void;
  9 + item?: ListVO;
  10 + onRefresh?: () => void;
  11 +}
  12 +
  13 +export default ({ visible, onCancel, item, onRefresh }: Props) => {
  14 + const [form] = Form.useForm();
  15 + const [saveLoading, setSaveLoading] = useState(false);
  16 + const [loading, setLoading] = useState<boolean>();
  17 + const [interveneList, setInterveneList] = useState<InterveneVO[]>([]);
  18 + const [currentIntervene, setCurrentIntervene] = useState<InterveneVO>();
  19 +
  20 + useEffect(() => {
  21 + if (visible) {
  22 + setLoading(true);
  23 + initData()
  24 + .then(() => {})
  25 + .catch((e) => message.error(e.message))
  26 + .finally(() => setLoading(false));
  27 + }
  28 + if (!visible) {
  29 + setSaveLoading(false);
  30 + setCurrentIntervene(undefined);
  31 + form?.resetFields();
  32 + }
  33 + }, [visible]);
  34 +
  35 + async function initData() {
  36 + const interveneRes = await queryInterveneSettingList({ interveneId: item?.interveneId });
  37 + const _interveneList = interveneRes?.data || [];
  38 + setInterveneList(_interveneList);
  39 + if (item?.id) {
  40 + const _currentIntervene = _interveneList.find((t) => t.code == item?.code);
  41 + setCurrentIntervene(_currentIntervene);
  42 + const thresholdRes = await queryThresholds({ id: item?.id });
  43 + form.setFieldsValue({
  44 + interveneId: { value: item?.interveneId, label: item?.name },
  45 + interveneList: thresholdRes?.data || [],
  46 + });
  47 + }
  48 + }
  49 +
  50 + function handleSave(feildValue: any) {
  51 + setSaveLoading(true);
  52 + const params = {
  53 + ...feildValue,
  54 + interveneId: feildValue?.interveneId.value,
  55 + id: item?.id,
  56 + };
  57 + save(params)
  58 + .then(() => {
  59 + message.success("操作成功");
  60 + onCancel?.();
  61 + onRefresh?.();
  62 + })
  63 + .catch((e) => message.error(e.message))
  64 + .finally(() => setSaveLoading(false));
  65 + }
  66 +
  67 + return (
  68 + <Modal
  69 + visible={visible}
  70 + onCancel={onCancel}
  71 + onOk={form.submit}
  72 + title={item?.id ? "编辑异常干预" : "新增异常干预"}
  73 + confirmLoading={saveLoading}
  74 + width="65%"
  75 + >
  76 + <Skeleton active loading={loading}>
  77 + <Form form={form} onFinish={handleSave} wrapperCol={{ span: 18 }} labelCol={{ span: 4 }}>
  78 + <Form.Item
  79 + name="interveneId"
  80 + label="异常干预项"
  81 + rules={[{ required: true, message: "异常干预项不能为空" }]}
  82 + getValueFromEvent={(e) => {
  83 + if (e.value != currentIntervene?.id) {
  84 + form.setFieldsValue({ interveneList: [] });
  85 + const _currentIntervene = interveneList.find((t) => e.value == t?.id);
  86 + setCurrentIntervene(_currentIntervene);
  87 + }
  88 + return e;
  89 + }}
  90 + >
  91 + <Select
  92 + placeholder="请选择"
  93 + showSearch
  94 + optionFilterProp="children"
  95 + labelInValue
  96 + filterOption={(input, option: any) => option?.children.indexOf(input) >= 0}
  97 + >
  98 + {interveneList.map((item) => (
  99 + <Select.Option value={item.id} key={item.id}>
  100 + {item.name}
  101 + </Select.Option>
  102 + ))}
  103 + </Select>
  104 + </Form.Item>
  105 + <Form.Item name="interveneList" label="干预设置" rules={[{ required: true, message: "干预设置不能为空" }]}>
  106 + <SettingList
  107 + saveLoading={!currentIntervene || saveLoading}
  108 + valueDesc={currentIntervene?.valueDesc}
  109 + valueUnit={currentIntervene?.valueUnit}
  110 + />
  111 + </Form.Item>
  112 + </Form>
  113 + </Skeleton>
  114 + </Modal>
  115 + );
  116 +};
... ...
src/pages/backlog/Intervention/components/SettingList.tsx 0 → 100644
  1 +import React, { memo, useEffect, useState } from "react";
  2 +import { Modal, Form, Input, Table, Select, Button, InputNumber } from "antd";
  3 +import { Item } from "../api";
  4 +import { PlusOutlined } from "@ant-design/icons";
  5 +import useInitial from "@/hooks/useInitail";
  6 +import * as roleApi from "@/pages/admin/Privilege/api";
  7 +import orderBy from "lodash/orderBy";
  8 +
  9 +interface Props {
  10 + onChange?: (value?: Item[]) => any;
  11 + value?: Item[];
  12 + saveLoading?: boolean;
  13 + valueDesc?: string;
  14 + valueUnit?: string;
  15 + disabled?: boolean;
  16 +}
  17 +
  18 +function Index({ value = [], onChange, saveLoading, valueUnit, valueDesc, disabled }: Props) {
  19 + const { data: roleList } = useInitial<roleApi.Item[], any>(roleApi.getAllRoleListApi, [], { roleTypes: 2 }, disabled);
  20 + const [form] = Form.useForm();
  21 + const [visible, setVisible] = useState(false);
  22 +
  23 + useEffect(() => {
  24 +
  25 + }, []);
  26 +
  27 + const onRemove = (index: number) => {
  28 + value.splice(index, 1);
  29 + onChange?.([...value]);
  30 + };
  31 +
  32 + const closeModal = () => {
  33 + setVisible(false);
  34 + form.resetFields();
  35 + };
  36 +
  37 + const openModal = (row: Item, index: number) => {
  38 + form.setFieldsValue({
  39 + index,
  40 + threshold: row.threshold,
  41 + role: { value: row.roleCode, label: row.roleName },
  42 + });
  43 + setVisible(true);
  44 + };
  45 +
  46 + const handleSave = (feildValue: any) => {
  47 + const index = feildValue.index;
  48 + const params = {
  49 + threshold: feildValue.threshold,
  50 + roleCode: feildValue?.role?.value || null,
  51 + roleName: feildValue?.role?.label || null,
  52 + };
  53 + if (typeof index == "number" && index >= 0) {
  54 + value[index] = params;
  55 + } else {
  56 + value.push(params);
  57 + }
  58 + const newValue = orderBy(value, ["threshold"], ["asc"]);
  59 + onChange?.(newValue);
  60 + closeModal();
  61 + };
  62 +
  63 + return (
  64 + <>
  65 + {!disabled ? (
  66 + <div style={{ display: "flex", justifyContent: "flex-end", marginBottom: 15 }}>
  67 + <Button type="primary" icon={<PlusOutlined />} disabled={saveLoading} onClick={() => setVisible(true)}>
  68 + 新增
  69 + </Button>
  70 + </div>
  71 + ) : null}
  72 + <Table dataSource={value} rowKey={(record: Item) => `${record.roleCode} ${record.threshold}`}>
  73 + <Table.Column
  74 + title="干预条件"
  75 + dataIndex="threshold"
  76 + align="center"
  77 + render={(text) => `${valueDesc || ""}≥${text}${valueUnit || ""}`}
  78 + />
  79 + <Table.Column title="干预角色" dataIndex="roleName" align="center" />
  80 + {!disabled ? (
  81 + <Table.Column
  82 + title="操作"
  83 + align="center"
  84 + render={(val, row: Item, index: number) => (
  85 + <>
  86 + <Button type="link" disabled={saveLoading} onClick={() => openModal(row, index)}>
  87 + 编辑
  88 + </Button>
  89 + <Button type="link" disabled={saveLoading} onClick={() => onRemove(index)}>
  90 + 删除
  91 + </Button>
  92 + </>
  93 + )}
  94 + />
  95 + ) : null}
  96 + </Table>
  97 + <Modal visible={visible} onCancel={closeModal} onOk={form.submit} title="干预设置">
  98 + <Form form={form} onFinish={handleSave} wrapperCol={{ span: 18 }} labelCol={{ span: 6 }}>
  99 + <Form.Item hidden name="index" label="index" rules={[{ required: false }]}>
  100 + <Input />
  101 + </Form.Item>
  102 + <Form.Item name="threshold" label="干预条件" rules={[{ required: true, message: "干预条件不能为空" }]}>
  103 + <InputNumber min={0} addonBefore={`${valueDesc || ""}≥`} addonAfter={valueUnit || ""} precision={0} />
  104 + </Form.Item>
  105 + <Form.Item name="role" label="干预角色" rules={[{ required: true, message: "干预角色不能为空" }]}>
  106 + <Select
  107 + placeholder="请选择"
  108 + showSearch
  109 + optionFilterProp="children"
  110 + labelInValue
  111 + filterOption={(input, option: any) => option?.children.indexOf(input) >= 0}
  112 + >
  113 + {roleList.map((item) => (
  114 + <Select.Option value={item.roleCode} key={item.id}>
  115 + {item.roleName}
  116 + </Select.Option>
  117 + ))}
  118 + </Select>
  119 + </Form.Item>
  120 + </Form>
  121 + </Modal>
  122 + </>
  123 + );
  124 +}
  125 +export default memo(Index);
... ...
src/pages/backlog/Intervention/components/SettingModal.tsx 0 → 100644
  1 +import React, { useEffect, useMemo } from "react";
  2 +import { Modal, Skeleton } from "antd";
  3 +import { queryThresholds, Item, InterveneVO, ListVO, queryInterveneSettingList } from "../api";
  4 +import useInitial from "@/hooks/useInitail";
  5 +import SettingList from "./SettingList";
  6 +
  7 +interface Props {
  8 + visible: boolean;
  9 + onCancel: () => void;
  10 + item?: ListVO;
  11 +}
  12 +
  13 +export default ({ visible, onCancel, item }: Props) => {
  14 + const { data, loading, setParams, setData } = useInitial<Item[], any>(
  15 + queryThresholds,
  16 + [],
  17 + { id: item?.id },
  18 + !item?.id
  19 + );
  20 + const {
  21 + data: interList,
  22 + loading: interLoading,
  23 + setParams: setParams2,
  24 + } = useInitial<InterveneVO[], any>(queryInterveneSettingList, [], { interveneId: item?.interveneId }, !item?.id);
  25 +
  26 + useEffect(() => {
  27 + if (visible && item?.id) {
  28 + setParams({ id: item?.id }, true);
  29 + setParams2({ interveneId: item?.interveneId }, true);
  30 + }
  31 + if (!visible) {
  32 + setData([]);
  33 + }
  34 + }, [visible]);
  35 +
  36 + const interveneVO = useMemo(() => interList.find((t) => t.code == item?.code), [interList]);
  37 +
  38 + return (
  39 + <Modal
  40 + visible={visible}
  41 + onCancel={onCancel}
  42 + cancelButtonProps={{ hidden: true }}
  43 + onOk={onCancel}
  44 + title="待办超时干预条件"
  45 + width="55%"
  46 + >
  47 + <Skeleton active loading={loading || interLoading}>
  48 + <SettingList
  49 + disabled
  50 + value={data || []}
  51 + valueDesc={interveneVO?.valueDesc}
  52 + valueUnit={interveneVO?.valueUnit}
  53 + />
  54 + </Skeleton>
  55 + </Modal>
  56 + );
  57 +};
... ...
src/pages/backlog/Intervention/index.tsx 0 → 100644
  1 +import React, { useCallback, useState } from "react";
  2 +import { PageHeaderWrapper } from "@ant-design/pro-layout";
  3 +import { Card, Table, Button, Select, Popconfirm, message, Input } from "antd";
  4 +import { PlusOutlined } from "@ant-design/icons";
  5 +import { queryPageList, ListVO, deleteData } from "./api";
  6 +import debounce from "lodash/debounce";
  7 +import usePagination from "@/hooks/usePagination";
  8 +import { systemListApi } from "@/pages/admin/Privilege/api";
  9 +import EditModal from "./components/EditModal";
  10 +import SettingModal from "./components/SettingModal";
  11 +import * as roleApi from "@/pages/admin/Privilege/api";
  12 +import useInitial from "@/hooks/useInitail";
  13 +
  14 +const Column = Table.Column;
  15 +
  16 +export default () => {
  17 + const { list, loading, paginationConfig, setParams } = usePagination<ListVO>(queryPageList, {}, {});
  18 + const { list: syslist } = usePagination(systemListApi, { current: 1, pageSize: 5000 });
  19 + const { data: roleList } = useInitial<roleApi.Item[], any>(roleApi.getAllRoleListApi, [], { roleTypes: 2 });
  20 +
  21 + const [visible, setVisible] = useState(false);
  22 + const [row, setRow] = useState<ListVO>();
  23 + const [settingVisible, setSettingVisible] = useState(false);
  24 +
  25 + const _onChange = debounce((val: string) => {
  26 + setParams({ keywords: val.trim(), current: 1 }, true);
  27 + }, 350);
  28 +
  29 + const _onChangeSys = debounce((e: any) => {
  30 + setParams({ sysId: e, current: 1 }, true);
  31 + }, 350);
  32 +
  33 + const _onChangeRole = debounce((e: any) => {
  34 + setParams({ roleCode: e, current: 1 }, true);
  35 + }, 350);
  36 +
  37 + const handleDelete = useCallback((row: ListVO) => {
  38 + deleteData(row.id)
  39 + .then(() => setParams({ current: 1 }, true))
  40 + .catch((e) => message.error(e.message));
  41 + }, []);
  42 +
  43 + return (
  44 + <PageHeaderWrapper title="异常干预">
  45 + <Card>
  46 + <div
  47 + style={{
  48 + display: "flex",
  49 + flexDirection: "row",
  50 + justifyContent: "space-between",
  51 + alignItems: "center",
  52 + marginBottom: 20,
  53 + }}
  54 + >
  55 + <div style={{ display: "flex" }}>
  56 + <Input.Search
  57 + allowClear
  58 + placeholder="干预事项名称"
  59 + onChange={(e) => _onChange(e.target.value)}
  60 + style={{ maxWidth: 180, marginRight: 15 }}
  61 + />
  62 +
  63 + <Select
  64 + allowClear
  65 + placeholder="归属系统"
  66 + style={{ width: 180, marginRight: 5 }}
  67 + onChange={(e: any) => _onChangeSys(e)}
  68 + filterOption={(input, option: any) => option?.children.indexOf(input) >= 0}
  69 + >
  70 + {syslist.map((item) => (
  71 + <Select.Option value={item.id!} key={item.id}>
  72 + {item.sysName}
  73 + </Select.Option>
  74 + ))}
  75 + </Select>
  76 +
  77 + <Select
  78 + allowClear
  79 + placeholder="角色"
  80 + style={{ width: 180, marginRight: 5 }}
  81 + onChange={(e: any) => _onChangeRole(e)}
  82 + filterOption={(input, option: any) => option?.children.indexOf(input) >= 0}
  83 + >
  84 + {roleList.map((item) => (
  85 + <Select.Option value={item.roleCode} key={item.id}>
  86 + {item.roleName}
  87 + </Select.Option>
  88 + ))}
  89 + </Select>
  90 + </div>
  91 +
  92 + <Button type="primary" icon={<PlusOutlined />} onClick={() => setVisible(true)}>
  93 + 新增
  94 + </Button>
  95 + </div>
  96 +
  97 + <Table
  98 + loading={loading}
  99 + dataSource={list}
  100 + pagination={paginationConfig}
  101 + rowKey={(record: ListVO) => String(record.id || record.code)}
  102 + >
  103 + <Column title="干预事项名称" dataIndex="name" align="center" />
  104 + <Column title="归属系统" dataIndex="applySysName" align="center" />
  105 +
  106 + <Column
  107 + title="干预条件和角色"
  108 + dataIndex="id"
  109 + align="center"
  110 + render={(text, record: ListVO) => (
  111 + <Button
  112 + type="link"
  113 + onClick={() => {
  114 + setRow(record);
  115 + setSettingVisible(true);
  116 + }}
  117 + >
  118 + 查看
  119 + </Button>
  120 + )}
  121 + />
  122 + <Column
  123 + title="操作"
  124 + align="center"
  125 + render={(val, row: ListVO) => (
  126 + <>
  127 + <Button
  128 + type="link"
  129 + onClick={() => {
  130 + setRow(row);
  131 + setVisible(true);
  132 + }}
  133 + >
  134 + 编辑
  135 + </Button>
  136 + <Popconfirm placement="top" title="确认删除?" onConfirm={() => handleDelete(row)}>
  137 + <Button type="link">删除</Button>
  138 + </Popconfirm>
  139 + </>
  140 + )}
  141 + />
  142 + </Table>
  143 + <EditModal
  144 + visible={visible}
  145 + item={row}
  146 + onCancel={() => {
  147 + setVisible(false);
  148 + setRow(undefined);
  149 + }}
  150 + onRefresh={() => setParams({}, true)}
  151 + />
  152 + <SettingModal
  153 + visible={settingVisible}
  154 + onCancel={() => {
  155 + setSettingVisible(false);
  156 + setRow(undefined);
  157 + }}
  158 + item={row}
  159 + />
  160 + </Card>
  161 + </PageHeaderWrapper>
  162 + );
  163 +};
... ...
src/pages/backlog/InterventionSetting/api.ts 0 → 100644
  1 +import request from "@/utils/request";
  2 +import { BACKLOG } from "@/utils/host";
  3 +import { http } from "@/typing/http";
  4 +import { PaginationParam } from "@/typing/common";
  5 +
  6 +export interface Params extends PaginationParam {
  7 + sysId?: number;
  8 + configId?: number;
  9 + keywords?: string;
  10 +}
  11 +
  12 +export interface ListVO {
  13 + id: number;
  14 + /** 干预事项编码 */
  15 + code: string;
  16 + /** 干预事项名称 */
  17 + name: string;
  18 + /** 待办配置id */
  19 + configId: number;
  20 + /** 待办编码 */
  21 + itemCode: string;
  22 + /** 待办名称 */
  23 + itemName: string;
  24 + /** 适用系统 */
  25 + applySysId: number;
  26 + /** 系统名称 */
  27 + applySysName: string;
  28 + /** 状态 0 禁用 1生效 */
  29 + status: number;
  30 + /** 干预阀值描述 */
  31 + valueDesc: string;
  32 + /** 干预阀值单位 */
  33 + valueUnit: string;
  34 +}
  35 +
  36 +export function querySettingList(params: Params): http.PromisePageResp<ListVO> {
  37 + return request.get(`${BACKLOG}/intervene/list`, { params });
  38 +}
  39 +
  40 +export function switchStatus(id: number, disable: boolean): http.PromisePageResp<void> {
  41 + let uri = `${BACKLOG}/intervene/enable`;
  42 + if (disable) {
  43 + uri = `${BACKLOG}/intervene/disable`;
  44 + }
  45 + return request.post(uri, { id }, { contentType: "form-urlencoded" });
  46 +}
  47 +
  48 +interface SavaParams {
  49 + id?: number;
  50 + name?: string;
  51 + configId?: number;
  52 + applySysId?: number;
  53 + valueDesc?: string;
  54 + valueUnit?: string;
  55 +}
  56 +
  57 +export function save(params: SavaParams): http.PromisePageResp<void> {
  58 + return request.post(`${BACKLOG}/intervene/save`, { ...params });
  59 +}
  60 +
  61 +export interface BacklogItemVO {
  62 + id: number;
  63 + itemCode: string;
  64 + itemName: string;
  65 +}
  66 +
  67 +export function queryBacklogList(): http.PromiseRespA<BacklogItemVO> {
  68 + return request.get<any>(`${BACKLOG}/config/list`, { params: { current: 1, pageSize: 5000 } }).then((res) => {
  69 + const data = res?.data?.data || [];
  70 + res.data = data;
  71 + return res;
  72 + });
  73 +}
  74 +
  75 +export function deleteSetting(id: number): http.PromisePageResp<ListVO> {
  76 + return request.get(`${BACKLOG}/intervene/delete`, { params: { id } });
  77 +}
... ...
src/pages/backlog/InterventionSetting/components/CreateModal.tsx 0 → 100644
  1 +import React, { useEffect, useState } from "react";
  2 +import { Modal, Form, Select, message, Input } from "antd";
  3 +import { save, ListVO, queryBacklogList, BacklogItemVO } from "../api";
  4 +import useInitial from "@/hooks/useInitail";
  5 +import { systemListApi } from "@/pages/admin/Privilege/api";
  6 +import usePagination from "@/hooks/usePagination";
  7 +
  8 +interface Props {
  9 + visible: boolean;
  10 + onCancel: () => void;
  11 + item?: ListVO;
  12 + onRefresh?: () => void;
  13 +}
  14 +
  15 +export default ({ visible, onCancel, item, onRefresh }: Props) => {
  16 + const [form] = Form.useForm();
  17 + const [saveLoading, setSaveLoading] = useState(false);
  18 + const { data: BacklogList } = useInitial<BacklogItemVO[], any>(queryBacklogList, [], {});
  19 + const { list: syslist } = usePagination(systemListApi, { current: 1, pageSize: 5000 });
  20 +
  21 + useEffect(() => {
  22 + if (visible && item?.id) {
  23 + form.setFieldsValue({
  24 + name: item.name,
  25 + configId: { value: item.configId, label: item.itemName },
  26 + applySysId: { value: item.applySysId, label: item.applySysName },
  27 + valueDesc: item.valueDesc,
  28 + valueUnit: item.valueUnit,
  29 + });
  30 + }
  31 + if (!visible) {
  32 + setSaveLoading(false);
  33 + form?.resetFields();
  34 + }
  35 + }, [visible]);
  36 +
  37 + function handleSave(feildValue: any) {
  38 + setSaveLoading(true);
  39 + const params = {
  40 + ...feildValue,
  41 + configId: feildValue?.configId.value,
  42 + applySysId: feildValue?.applySysId.value,
  43 + id: item?.id,
  44 + };
  45 + save(params)
  46 + .then(() => {
  47 + message.success("操作成功");
  48 + onCancel?.();
  49 + onRefresh?.();
  50 + })
  51 + .catch((e) => message.error(e.message))
  52 + .finally(() => setSaveLoading(false));
  53 + }
  54 +
  55 + return (
  56 + <Modal
  57 + visible={visible}
  58 + onCancel={onCancel}
  59 + onOk={form.submit}
  60 + title={item?.id ? "编辑异常干预项" : "新增异常干预项"}
  61 + confirmLoading={saveLoading}
  62 + width="65%"
  63 + >
  64 + <Form form={form} onFinish={handleSave} wrapperCol={{ span: 18 }} labelCol={{ span: 4 }}>
  65 + <Form.Item name="name" label="干预事项名称" rules={[{ required: true, message: "干预事项名称不能为空" }]}>
  66 + <Input placeholder="请输入干预事项名称" />
  67 + </Form.Item>
  68 + <Form.Item name="configId" label="干预代办" rules={[{ required: true, message: "待办不能为空" }]}>
  69 + <Select
  70 + placeholder="请选择"
  71 + disabled={!!item?.id}
  72 + showSearch
  73 + optionFilterProp="children"
  74 + labelInValue
  75 + filterOption={(input, option: any) => option?.children.indexOf(input) >= 0}
  76 + >
  77 + {BacklogList.map((item) => (
  78 + <Select.Option value={item.id} key={item.id}>
  79 + {item.itemName}
  80 + </Select.Option>
  81 + ))}
  82 + </Select>
  83 + </Form.Item>
  84 + <Form.Item name="applySysId" label="归属系统" rules={[{ required: true, message: "归属系统不能为空" }]}>
  85 + <Select
  86 + placeholder="请选择"
  87 + disabled={!!item?.id}
  88 + showSearch
  89 + optionFilterProp="children"
  90 + labelInValue
  91 + filterOption={(input, option: any) => option?.children.indexOf(input) >= 0}
  92 + >
  93 + {syslist.map((item) => (
  94 + <Select.Option value={item.id} key={item.id}>
  95 + {item.sysName}
  96 + </Select.Option>
  97 + ))}
  98 + </Select>
  99 + </Form.Item>
  100 + <Form.Item name="valueDesc" label="干预阀值描述" rules={[{ required: true, message: "干预阀值描述不能为空" }]}>
  101 + <Input placeholder="请输入干预阀值描述" />
  102 + </Form.Item>
  103 + <Form.Item name="valueUnit" label="单位" rules={[{ required: true, message: "单位不能为空" }]}>
  104 + <Input placeholder="请输入单位" />
  105 + </Form.Item>
  106 + </Form>
  107 + </Modal>
  108 + );
  109 +};
... ...
src/pages/backlog/InterventionSetting/index.tsx 0 → 100644
  1 +import React, { useCallback, useState } from "react";
  2 +import { PageHeaderWrapper } from "@ant-design/pro-layout";
  3 +import { Card, Table, Button, Input, Select, Popconfirm, Badge, message } from "antd";
  4 +import { PlusOutlined } from "@ant-design/icons";
  5 +import { querySettingList, ListVO, switchStatus, deleteSetting } from "./api";
  6 +import debounce from "lodash/debounce";
  7 +import usePagination from "@/hooks/usePagination";
  8 +import { systemListApi } from "@/pages/admin/Privilege/api";
  9 +import CreateModal from "./components/CreateModal";
  10 +
  11 +const Column = Table.Column;
  12 +const Search = Input.Search;
  13 +
  14 +export default () => {
  15 + const { list, loading, paginationConfig, setParams } = usePagination<ListVO>(querySettingList, [], {});
  16 + const { list: syslist } = usePagination(systemListApi, { current: 1, pageSize: 5000 });
  17 +
  18 + const [visible, setVisible] = useState(false);
  19 + const [row, setRow] = useState<ListVO>();
  20 +
  21 + const _onChange = debounce((val: string) => {
  22 + setParams({ keywords: val.trim(), current: 1 }, true);
  23 + }, 350);
  24 +
  25 + const _onChangeSys = debounce((e: any) => {
  26 + setParams({ sysId: e, current: 1 }, true);
  27 + }, 350);
  28 +
  29 + const switchDisable = useCallback((row: ListVO) => {
  30 + switchStatus(row.id, row.status == 1)
  31 + .then(() => setParams({ current: 1 }, true))
  32 + .catch((e) => message.error(e.message));
  33 + }, []);
  34 +
  35 + const deleteData = useCallback((row: ListVO) => {
  36 + deleteSetting(row.id)
  37 + .then(() => setParams({ current: 1 }, true))
  38 + .catch((e) => message.error(e.message));
  39 + }, []);
  40 +
  41 + enum StatusEnum {
  42 + "禁用",
  43 + "有效",
  44 + }
  45 +
  46 + return (
  47 + <PageHeaderWrapper title="异常干预配置">
  48 + <Card>
  49 + <div
  50 + style={{
  51 + display: "flex",
  52 + flexDirection: "row",
  53 + justifyContent: "space-between",
  54 + alignItems: "center",
  55 + marginBottom: 20,
  56 + }}
  57 + >
  58 + <div style={{ display: "flex" }}>
  59 + <Search
  60 + allowClear
  61 + placeholder="干预事项名称"
  62 + onChange={(e) => _onChange(e.target.value)}
  63 + style={{ maxWidth: 260, marginRight: 15 }}
  64 + />
  65 +
  66 + <Select
  67 + allowClear
  68 + placeholder="归属系统"
  69 + style={{ width: 260, marginRight: 5 }}
  70 + onChange={(e: any) => _onChangeSys(e)}
  71 + >
  72 + {syslist.map((item) => (
  73 + <Select.Option value={item.id!} key={item.id}>
  74 + {item.sysName}
  75 + </Select.Option>
  76 + ))}
  77 + </Select>
  78 + </div>
  79 +
  80 + <Button type="primary" icon={<PlusOutlined />} onClick={() => setVisible(true)}>
  81 + 新增
  82 + </Button>
  83 + </div>
  84 +
  85 + <Table
  86 + loading={loading}
  87 + dataSource={list}
  88 + pagination={paginationConfig}
  89 + rowKey={(record: ListVO) => String(record.id || record.code)}
  90 + >
  91 + <Column title="干预事项名称" dataIndex="name" align="center" />
  92 + <Column title="干预事项编码" dataIndex="code" align="center" />
  93 + <Column title="干预待办" dataIndex="itemName" align="center" />
  94 + <Column title="归属系统" dataIndex="applySysName" align="center" />
  95 + <Column
  96 + title="状态"
  97 + dataIndex="status"
  98 + align="center"
  99 + render={(text, record: ListVO) => (
  100 + <Badge status={record.status == 0 ? "error" : "processing"} text={StatusEnum[record.status]} />
  101 + )}
  102 + />
  103 + <Column title="干预阀值描述" dataIndex="valueDesc" align="center" />
  104 + <Column title="干预阀值单位" dataIndex="valueUnit" align="center" />
  105 +
  106 + <Column
  107 + title="操作"
  108 + align="center"
  109 + render={(val, row: ListVO) => (
  110 + <>
  111 + <Button
  112 + type="link"
  113 + onClick={() => {
  114 + setRow(row);
  115 + setVisible(true);
  116 + }}
  117 + >
  118 + 编辑
  119 + </Button>
  120 + <Popconfirm
  121 + placement="top"
  122 + title={`确认${row.status == 0 ? "启用" : "禁用"}?`}
  123 + onConfirm={() => switchDisable(row)}
  124 + >
  125 + <Button danger={row.status == 1} type="link">
  126 + {row.status == 0 ? "启用" : "禁用"}
  127 + </Button>
  128 + </Popconfirm>
  129 + <Popconfirm placement="top" title="确认删除?" onConfirm={() => deleteData(row)}>
  130 + <Button danger={row.status == 1} type="link">
  131 + 删除
  132 + </Button>
  133 + </Popconfirm>
  134 + </>
  135 + )}
  136 + />
  137 + </Table>
  138 + <CreateModal
  139 + item={row}
  140 + visible={visible}
  141 + onCancel={() => {
  142 + setVisible(false);
  143 + setRow(undefined);
  144 + }}
  145 + onRefresh={() => setParams({}, true)}
  146 + />
  147 + </Card>
  148 + </PageHeaderWrapper>
  149 + );
  150 +};
... ...
src/pages/backlog/OverIntervention/Index.tsx 0 → 100644
  1 +import React, { useCallback, useState } from "react";
  2 +import { PageHeaderWrapper } from "@ant-design/pro-layout";
  3 +import { Card, Table, Button, Input, Select, Popconfirm, message } from "antd";
  4 +import { PlusOutlined } from "@ant-design/icons";
  5 +import { queryPageList, ListVO, queryWorkTypeList, deleteData } from "./api";
  6 +import debounce from "lodash/debounce";
  7 +import usePagination from "@/hooks/usePagination";
  8 +import { systemListApi } from "@/pages/admin/Privilege/api";
  9 +import EditModal from "./components/EditModal";
  10 +import SettingModal from "./components/SettingModal";
  11 +
  12 +const Column = Table.Column;
  13 +const Search = Input.Search;
  14 +
  15 +export default () => {
  16 + const { list, loading, paginationConfig, setParams } = usePagination<ListVO>(queryPageList, {}, {});
  17 + const { list: syslist } = usePagination(systemListApi, { current: 1, pageSize: 5000 });
  18 + const { list: workList } = usePagination(queryWorkTypeList, { current: 1, pageSize: 5000 });
  19 +
  20 + const [visible, setVisible] = useState(false);
  21 + const [row, setRow] = useState<ListVO>();
  22 + const [settingVisible, setSettingVisible] = useState(false);
  23 +
  24 + const _onChange = debounce((val: string) => {
  25 + setParams({ keywords: val.trim(), current: 1 }, true);
  26 + }, 350);
  27 +
  28 + const _onChangeSys = debounce((e: any) => {
  29 + setParams({ sysId: e, current: 1 }, true);
  30 + }, 350);
  31 +
  32 + const _onChangeWork = debounce((e: any) => {
  33 + setParams({ workType: e, current: 1 }, true);
  34 + }, 350);
  35 +
  36 + const handleDelete = useCallback((row: ListVO) => {
  37 + deleteData(row.id)
  38 + .then(() => setParams({ current: 1 }, true))
  39 + .catch((e) => message.error(e.message));
  40 + }, []);
  41 +
  42 + return (
  43 + <PageHeaderWrapper title="待办超时干预">
  44 + <Card>
  45 + <div
  46 + style={{
  47 + display: "flex",
  48 + flexDirection: "row",
  49 + justifyContent: "space-between",
  50 + alignItems: "center",
  51 + marginBottom: 20,
  52 + }}
  53 + >
  54 + <div style={{ display: "flex" }}>
  55 + <Search
  56 + allowClear
  57 + placeholder="待办名称"
  58 + onChange={(e) => _onChange(e.target.value)}
  59 + style={{ maxWidth: 260, marginRight: 15 }}
  60 + />
  61 +
  62 + <Select
  63 + allowClear
  64 + placeholder="归属系统"
  65 + style={{ width: 260, marginRight: 5 }}
  66 + onChange={(e: any) => _onChangeSys(e)}
  67 + >
  68 + {syslist.map((item) => (
  69 + <Select.Option value={item.id!} key={item.id}>
  70 + {item.sysName}
  71 + </Select.Option>
  72 + ))}
  73 + </Select>
  74 +
  75 + <Select
  76 + allowClear
  77 + placeholder="工作类型"
  78 + style={{ width: 260, marginRight: 5 }}
  79 + onChange={(e: any) => _onChangeWork(e)}
  80 + >
  81 + {workList.map((item) => (
  82 + <Select.Option value={item.id!} key={item.id}>
  83 + {item.name}
  84 + </Select.Option>
  85 + ))}
  86 + </Select>
  87 + </div>
  88 +
  89 + <Button type="primary" icon={<PlusOutlined />} onClick={() => setVisible(true)}>
  90 + 新增
  91 + </Button>
  92 + </div>
  93 +
  94 + <Table
  95 + loading={loading}
  96 + dataSource={list}
  97 + pagination={paginationConfig}
  98 + rowKey={(record: ListVO) => String(record.id || record.code)}
  99 + >
  100 + <Column title="待办名称" dataIndex="itemName" align="center" />
  101 + <Column title="归属系统" dataIndex="applySysName" align="center" />
  102 + <Column title="工作类型" dataIndex="workTypeName" align="center" />
  103 +
  104 + <Column
  105 + title="待办超时干预"
  106 + dataIndex="id"
  107 + align="center"
  108 + render={(text, record: ListVO) => (
  109 + <Button
  110 + type="link"
  111 + onClick={() => {
  112 + setRow(record);
  113 + setSettingVisible(true);
  114 + }}
  115 + >
  116 + 查看
  117 + </Button>
  118 + )}
  119 + />
  120 + <Column
  121 + title="操作"
  122 + align="center"
  123 + render={(val, row: ListVO) => (
  124 + <>
  125 + <Button
  126 + type="link"
  127 + onClick={() => {
  128 + setRow(row);
  129 + setVisible(true);
  130 + }}
  131 + >
  132 + 编辑
  133 + </Button>
  134 + <Popconfirm placement="top" title="确认删除?" onConfirm={() => handleDelete(row)}>
  135 + <Button type="link">删除</Button>
  136 + </Popconfirm>
  137 + </>
  138 + )}
  139 + />
  140 + </Table>
  141 + <EditModal
  142 + visible={visible}
  143 + item={row}
  144 + onCancel={() => {
  145 + setVisible(false);
  146 + setRow(undefined);
  147 + }}
  148 + onRefresh={() => setParams({}, true)}
  149 + />
  150 + <SettingModal
  151 + visible={settingVisible}
  152 + onCancel={() => {
  153 + setSettingVisible(false);
  154 + setRow(undefined);
  155 + }}
  156 + id={row?.id}
  157 + />
  158 + </Card>
  159 + </PageHeaderWrapper>
  160 + );
  161 +};
... ...
src/pages/backlog/OverIntervention/api.ts 0 → 100644
  1 +import request from "@/utils/request";
  2 +import { BACKLOG } from "@/utils/host";
  3 +import { http } from "@/typing/http";
  4 +import { PaginationParam } from "@/typing/common";
  5 +
  6 +export function queryApplyShops(id?: number): http.PromiseResp<{ shopId: number; shopName: string }[]> {
  7 + return request.get(`${BACKLOG}/efficiency/apply/shops`, { params: { id } });
  8 +}
  9 +
  10 +export interface ListVO {
  11 + id: number;
  12 + /** 干预事项编码 */
  13 + code: string;
  14 + /** 干预事项名称 */
  15 + name: string;
  16 + /** 待办配置id */
  17 + configId: number;
  18 + /** 待办名称 */
  19 + itemName: string;
  20 + /** 系统id */
  21 + applySysId: number;
  22 + /** 系统名称 */
  23 + applySysName: string;
  24 + createTime: number;
  25 +}
  26 +
  27 +export interface Params extends PaginationParam {
  28 + sysId?: number;
  29 + workType?: number;
  30 + roleCode?: string;
  31 + keywords?: string;
  32 +}
  33 +
  34 +export function queryPageList(params?: Params): http.PromisePageResp<ListVO> {
  35 + return request.get(`${BACKLOG}/over/list`, { params });
  36 +}
  37 +
  38 +export interface OptionVO {
  39 + id: number;
  40 + name: string;
  41 +}
  42 +
  43 +export function queryWorkTypeList(): http.PromisePageResp<OptionVO> {
  44 + return request.get(`${BACKLOG}/work/type/list`);
  45 +}
  46 +
  47 +export interface SaveParams {
  48 + id?: number;
  49 + /** 代办配置id */
  50 + configId?: number;
  51 + interveneList?: Item[];
  52 +}
  53 +
  54 +export interface Item {
  55 + /** 触发阀值 */
  56 + threshold: number;
  57 + /** 角色编码 */
  58 + roleCode: string;
  59 + /** 角色名称 */
  60 + roleName: string;
  61 +}
  62 +
  63 +export function save(params: SaveParams): http.PromiseResp<void> {
  64 + return request.post(`${BACKLOG}/over/save`, { ...params });
  65 +}
  66 +
  67 +export interface BacklogItemVO {
  68 + id: number;
  69 + itemCode: string;
  70 + itemName: string;
  71 +}
  72 +
  73 +export function queryBacklogList(): http.PromiseRespA<BacklogItemVO> {
  74 + return request.get(`${BACKLOG}/config/over/list`);
  75 +}
  76 +
  77 +export function queryThresholds(params: any): http.PromiseRespA<Item> {
  78 + return request.get(`${BACKLOG}/over/notify/thresholds`, { params });
  79 +}
  80 +
  81 +export function deleteData(id?: number): http.PromiseResp<void> {
  82 + return request.get(`${BACKLOG}/over/delete`, { params: { id } });
  83 +}
... ...
src/pages/backlog/OverIntervention/components/EditModal.tsx 0 → 100644
  1 +import React, { useEffect, useState } from "react";
  2 +import { Modal, Form, Select, message, Skeleton } from "antd";
  3 +import { save, ListVO, queryBacklogList, BacklogItemVO, queryThresholds } from "../api";
  4 +import useInitial from "@/hooks/useInitail";
  5 +import SettingList from "./SettingList";
  6 +
  7 +interface Props {
  8 + visible: boolean;
  9 + onCancel: () => void;
  10 + item?: ListVO;
  11 + onRefresh?: () => void;
  12 +}
  13 +
  14 +export default ({ visible, onCancel, item, onRefresh }: Props) => {
  15 + const [form] = Form.useForm();
  16 + const [saveLoading, setSaveLoading] = useState(false);
  17 + const [loading, setLoading] = useState<boolean>();
  18 + const { data: BacklogList, setParams } = useInitial<BacklogItemVO[], any>(queryBacklogList, [], {});
  19 +
  20 + useEffect(() => {
  21 + if (visible) {
  22 + setParams({}, true);
  23 + }
  24 + if (visible && item?.id) {
  25 + setLoading(true);
  26 + queryThresholds({ id: item?.id })
  27 + .then((res) => {
  28 + form.setFieldsValue({
  29 + configId: { value: item.configId, label: item.itemName },
  30 + interveneList: res.data || [],
  31 + });
  32 + setLoading(false);
  33 + })
  34 + .catch((e) => {
  35 + message.error(`干预配置查询失败:${e.message}`);
  36 + setLoading(false);
  37 + });
  38 + }
  39 + if (!visible) {
  40 + setSaveLoading(false);
  41 + form?.resetFields();
  42 + }
  43 + }, [visible]);
  44 +
  45 + function handleSave(feildValue: any) {
  46 + setSaveLoading(true);
  47 + const params = {
  48 + ...feildValue,
  49 + configId: feildValue?.configId.value,
  50 + id: item?.id,
  51 + };
  52 + save(params)
  53 + .then(() => {
  54 + message.success("操作成功");
  55 + onCancel?.();
  56 + onRefresh?.();
  57 + })
  58 + .catch((e) => message.error(e.message))
  59 + .finally(() => setSaveLoading(false));
  60 + }
  61 +
  62 + return (
  63 + <Modal
  64 + visible={visible}
  65 + onCancel={onCancel}
  66 + onOk={form.submit}
  67 + title={item?.id ? "编辑超时干预" : "新增超时干预"}
  68 + confirmLoading={saveLoading}
  69 + width="65%"
  70 + >
  71 + <Skeleton active loading={loading}>
  72 + <Form form={form} onFinish={handleSave} wrapperCol={{ span: 18 }} labelCol={{ span: 4 }}>
  73 + <Form.Item name="configId" label="待办" rules={[{ required: true, message: "待办不能为空" }]}>
  74 + <Select
  75 + placeholder="请选择"
  76 + disabled={!!item?.id}
  77 + showSearch
  78 + optionFilterProp="children"
  79 + labelInValue
  80 + filterOption={(input, option: any) => option?.children.indexOf(input) >= 0}
  81 + >
  82 + {BacklogList.map((item) => (
  83 + <Select.Option value={item.id} key={item.id}>
  84 + {item.itemName}
  85 + </Select.Option>
  86 + ))}
  87 + </Select>
  88 + </Form.Item>
  89 + <Form.Item name="interveneList" label="干预设置" rules={[{ required: true, message: "干预设置不能为空" }]}>
  90 + <SettingList saveLoading={saveLoading} />
  91 + </Form.Item>
  92 + </Form>
  93 + </Skeleton>
  94 + </Modal>
  95 + );
  96 +};
... ...
src/pages/backlog/OverIntervention/components/SettingList.tsx 0 → 100644
  1 +import React, { useState } from "react";
  2 +import { Modal, Form, Input, Table, Select, Button, InputNumber } from "antd";
  3 +import { Item } from "../api";
  4 +import { PlusOutlined } from "@ant-design/icons";
  5 +import useInitial from "@/hooks/useInitail";
  6 +import * as roleApi from "@/pages/admin/Privilege/api";
  7 +import orderBy from "lodash/orderBy";
  8 +
  9 +interface Props {
  10 + onChange?: (value?: Item[]) => any;
  11 + value?: Item[];
  12 + saveLoading?: boolean;
  13 + disabled?: boolean;
  14 +}
  15 +
  16 +export default ({ value = [], onChange, saveLoading, disabled }: Props) => {
  17 + const { data: roleList } = useInitial<roleApi.Item[], any>(roleApi.getAllRoleListApi, [], { roleTypes: 2 }, disabled);
  18 + const [form] = Form.useForm();
  19 + const [visible, setVisible] = useState(false);
  20 +
  21 + const onRemove = (index: number) => {
  22 + value.splice(index, 1);
  23 + onChange?.([...value]);
  24 + };
  25 +
  26 + const closeModal = () => {
  27 + setVisible(false);
  28 + form.resetFields();
  29 + };
  30 +
  31 + const openModal = (row: Item, index: number) => {
  32 + form.setFieldsValue({
  33 + index,
  34 + threshold: row.threshold,
  35 + role: { value: row.roleCode, label: row.roleName },
  36 + });
  37 + setVisible(true);
  38 + };
  39 +
  40 + const handleSave = (feildValue: any) => {
  41 + const index = feildValue.index;
  42 + const params = {
  43 + threshold: feildValue.threshold,
  44 + roleCode: feildValue?.role?.value || null,
  45 + roleName: feildValue?.role?.label || null,
  46 + };
  47 + if (typeof index == "number" && index >= 0) {
  48 + value[index] = params;
  49 + } else {
  50 + value.push(params);
  51 + }
  52 + const newValue = orderBy(value, ["threshold"], ["asc"]);
  53 + onChange?.(newValue);
  54 + closeModal();
  55 + };
  56 +
  57 + return (
  58 + <>
  59 + {!disabled ? (
  60 + <div style={{ display: "flex", justifyContent: "flex-end", marginBottom: 15 }}>
  61 + <Button type="primary" icon={<PlusOutlined />} disabled={saveLoading} onClick={() => setVisible(true)}>
  62 + 新增
  63 + </Button>
  64 + </div>
  65 + ) : null}
  66 + <Table dataSource={value} rowKey={(record: Item) => `${record.roleCode} ${record.threshold}`}>
  67 + <Table.Column title="干预条件" dataIndex="threshold" align="center" render={(text) => `待办超时≥${text}天`} />
  68 + <Table.Column title="干预角色" dataIndex="roleName" align="center" />
  69 + {!disabled ? (
  70 + <Table.Column
  71 + title="操作"
  72 + align="center"
  73 + render={(val, row: Item, index: number) => (
  74 + <>
  75 + <Button type="link" disabled={saveLoading} onClick={() => openModal(row, index)}>
  76 + 编辑
  77 + </Button>
  78 + <Button type="link" disabled={saveLoading} onClick={() => onRemove(index)}>
  79 + 删除
  80 + </Button>
  81 + </>
  82 + )}
  83 + />
  84 + ) : null}
  85 + </Table>
  86 + <Modal visible={visible} onCancel={closeModal} onOk={form.submit} title="干预设置">
  87 + <Form form={form} onFinish={handleSave} wrapperCol={{ span: 18 }} labelCol={{ span: 6 }}>
  88 + <Form.Item hidden name="index" label="index" rules={[{ required: false }]}>
  89 + <Input />
  90 + </Form.Item>
  91 + <Form.Item name="threshold" label="干预条件" rules={[{ required: true, message: "干预条件不能为空" }]}>
  92 + <InputNumber min={0} addonBefore="待办超时≥" addonAfter="天" precision={0} />
  93 + </Form.Item>
  94 + <Form.Item name="role" label="干预角色" rules={[{ required: true, message: "干预角色不能为空" }]}>
  95 + <Select
  96 + placeholder="请选择"
  97 + showSearch
  98 + optionFilterProp="children"
  99 + labelInValue
  100 + filterOption={(input, option: any) => option?.children.indexOf(input) >= 0}
  101 + >
  102 + {roleList.map((item) => (
  103 + <Select.Option value={item.roleCode} key={item.id}>
  104 + {item.roleName}
  105 + </Select.Option>
  106 + ))}
  107 + </Select>
  108 + </Form.Item>
  109 + </Form>
  110 + </Modal>
  111 + </>
  112 + );
  113 +};
... ...
src/pages/backlog/OverIntervention/components/SettingModal.tsx 0 → 100644
  1 +import React, { useEffect, useState } from "react";
  2 +import { Modal, Skeleton } from "antd";
  3 +import { queryThresholds, Item } from "../api";
  4 +import useInitial from "@/hooks/useInitail";
  5 +import SettingList from "./SettingList";
  6 +
  7 +interface Props {
  8 + visible: boolean;
  9 + onCancel: () => void;
  10 + id?: number;
  11 +}
  12 +
  13 +export default ({ visible, onCancel, id }: Props) => {
  14 + const { data, loading, setParams, setData } = useInitial<Item[], any>(queryThresholds, [], { id }, !id);
  15 +
  16 + useEffect(() => {
  17 + if (visible && id) {
  18 + setParams({ id }, true);
  19 + }
  20 + if (!visible) {
  21 + setData([]);
  22 + }
  23 + }, [visible]);
  24 +
  25 + return (
  26 + <Modal
  27 + visible={visible}
  28 + onCancel={onCancel}
  29 + cancelButtonProps={{ hidden: true }}
  30 + onOk={onCancel}
  31 + title="待办超时干预条件"
  32 + width="55%"
  33 + >
  34 + <Skeleton active loading={loading}>
  35 + <SettingList disabled value={data || []} />
  36 + </Skeleton>
  37 + </Modal>
  38 + );
  39 +};
... ...
src/pages/backlog/TaskTime/api.ts
1 1 import request from "@/utils/request";
2   -import { common } from "@/typing/common";
3   -import { BACKLOG } from "@/utils/host";
  2 +import common from "@/typing/common";
  3 +import { BACKLOG, OOP_HOST } from "@/utils/host";
4 4 import { http } from "@/typing/http";
5 5  
6 6 export interface ListParams extends common.PaginationParam {
7 7 keywords?: string;
8 8 configId?: number;
  9 + /** 适用门店类型 1全部门店 2部分门店 */
  10 + applyType?: number;
9 11 }
10 12  
11 13 export interface ListVO {
... ... @@ -25,6 +27,7 @@ export interface ListVO {
25 27 extendUnit?: number;
26 28 itemCode?: string; //待办编码
27 29 itemName?: string; //待办名称
  30 + applyType?: number;
28 31 }
29 32 export interface ItemListVO {
30 33 /** id 有表示编辑,为空表示新增 */
... ... @@ -41,6 +44,8 @@ export interface ItemListVO {
41 44 extendValue?: number;
42 45 /** 延长时间单位 */
43 46 extendUnit?: number;
  47 + /** 适用门店类型 1全部门店 2部分门店 */
  48 + applyType?: number;
44 49 }
45 50  
46 51 export interface ToDoListVO {
... ... @@ -73,6 +78,10 @@ export interface ToDoListVO {
73 78 /** 动态模版 */
74 79 dynamicTemp?: string;
75 80 }
  81 +export enum ApplyType {
  82 + "全部门店" = 1,
  83 + "部分门店",
  84 +}
76 85  
77 86 /**
78 87 * 待办时效列表
... ... @@ -131,3 +140,16 @@ export interface SaveParams {
131 140 export function saveTimeApi(params: SaveParams) {
132 141 return request.post(`${BACKLOG}/efficiency/save`, { ...params });
133 142 }
  143 +
  144 +export function queryApplyShops(id?: number): http.PromiseResp<{ shopId: number; shopName: string }[]> {
  145 + return request.get(`${BACKLOG}/efficiency/apply/shops`, { params: { id } });
  146 +}
  147 +
  148 +export interface OptionVO {
  149 + id: number;
  150 + name: string;
  151 +}
  152 +
  153 +export function queryWorkTypeList(): http.PromisePageResp<OptionVO> {
  154 + return request.get(`${BACKLOG}/work/type/list`);
  155 +}
134 156 \ No newline at end of file
... ...
src/pages/backlog/TaskTime/components/CreateModal.tsx
1 1 import React, { useEffect, useState } from "react";
2   -import { Modal, Form, Input, message, Select } from "antd";
3   -import { saveTimeApi, ItemListVO, getTimeConfigListApi, ListVO, ListParams } from "../api";
  2 +import { Modal, Form, Input, message, Select, Radio } from "antd";
  3 +import { saveTimeApi, ItemListVO, getTimeConfigListApi, ListVO, ListParams, ApplyType, queryApplyShops } from "../api";
4 4 import { TimeUnitEnum } from "../entity";
5   -
6 5 import useInitial from "@/hooks/useInitail";
  6 +import ShopSelectNew from "@/components/ShopSelectNew";
7 7  
  8 +const RadioGroup = Radio.Group;
8 9 const { Option } = Select;
9 10  
10   -// interface ToDo {
11   -// id: number;
12   -// itemCode: string;
13   -// itemName: string;
14   -// }
15 11 interface Props {
16 12 visible: boolean;
17 13 onCancel: () => void;
18 14 onRefreshing: () => void;
19   - item: ItemListVO;
  15 + item?: ListVO | ItemListVO;
20 16 }
21 17  
22 18 export default function CreateModal({ visible, onCancel, item, onRefreshing }: Props) {
... ... @@ -24,19 +20,15 @@ export default function CreateModal({ visible, onCancel, item, onRefreshing }: P
24 20 const [saveLoading, setSaveLoading] = useState(false);
25 21 const [extendDisabled, setExtendDisabled] = useState(true);
26 22 // 配置过待办时效获取待办名称列表
27   - const { data: todoList, setParams } = useInitial<ListVO[], ListParams>(getTimeConfigListApi, [], {});
28   - console.log("item:", item);
  23 + const { data: todoList, setParams } = useInitial<ListVO[], ListParams>(getTimeConfigListApi, [], {
  24 + applyType: ApplyType.全部门店,
  25 + });
29 26 useEffect(() => {
30   - if (visible && item.id) {
31   - setParams({ configId: item.configId }, true);
32   - form.setFieldsValue({
33   - // configIds: item.configId, // 待办名称
34   - configIds: { label: item.configName, value: item.configId }, // 待办名称
35   - periodValue: item.periodValue, //待办时效
36   - periodUnit: item.periodUnit, // 待办时效单位
37   - extendValue: item.extendValue, // 延长时间
38   - extendUnit: item.extendUnit, // 延长时间单位
39   - });
  27 + if (visible && item?.id) {
  28 + setParams({ configId: item.configId, applyType: item.applyType }, true);
  29 + if (item.id) {
  30 + initData(item.id);
  31 + }
40 32 }
41 33 if (!visible) {
42 34 setSaveLoading(false);
... ... @@ -44,18 +36,40 @@ export default function CreateModal({ visible, onCancel, item, onRefreshing }: P
44 36 }
45 37 }, [visible]);
46 38  
  39 + function initData(id: number) {
  40 + queryApplyShops(id)
  41 + .then((res) => {
  42 + const shop = (res.data || []).map((t) => ({ value: t.shopId, label: t.shopName }));
  43 + form.setFieldsValue({
  44 + configIds: { value: item?.configId, label: item?.configName },
  45 + periodValue: item?.periodValue, //待办时效
  46 + periodUnit: item?.periodUnit, // 待办时效单位
  47 + extendValue: item?.extendValue, // 延长时间
  48 + extendUnit: item?.extendUnit, // 延长时间单位
  49 + applyType: item?.applyType,
  50 + applyShops: shop,
  51 + });
  52 + })
  53 + .catch((e) => {
  54 + form.setFieldsValue({
  55 + configIds: { value: item?.configId, label: item?.configName },
  56 + periodValue: item?.periodValue, //待办时效
  57 + periodUnit: item?.periodUnit, // 待办时效单位
  58 + extendValue: item?.extendValue, // 延长时间
  59 + extendUnit: item?.extendUnit, // 延长时间单位
  60 + applyType: item?.applyType,
  61 + });
  62 + });
  63 + }
  64 +
47 65 function handleSave(feildValue: any) {
48 66 setSaveLoading(true);
49 67 const params = {
50 68 ...feildValue,
51   - id: item.id,
  69 + configIds: feildValue?.configIds?.value || null,
  70 + id: item?.id,
  71 + applyShops: (feildValue.applyShops || []).map((t: any) => t.value).join(","),
52 72 };
53   - if (!item.id) {
54   - const configIds = feildValue.configIds.join(",");
55   - params.configIds = configIds;
56   - } else {
57   - params.configIds = feildValue.configIds.value;
58   - }
59 73 saveTimeApi(params)
60 74 .then((res) => {
61 75 message.success("操作成功!");
... ... @@ -69,10 +83,10 @@ export default function CreateModal({ visible, onCancel, item, onRefreshing }: P
69 83 });
70 84 }
71 85 useEffect(() => {
72   - if (item.extendValue) {
  86 + if (item?.extendValue) {
73 87 setExtendDisabled(false);
74 88 }
75   - }, [item.extendValue]);
  89 + }, [item?.extendValue]);
76 90  
77 91 const _onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
78 92 if (e.target.value) {
... ... @@ -90,25 +104,67 @@ export default function CreateModal({ visible, onCancel, item, onRefreshing }: P
90 104 visible={visible}
91 105 onCancel={onCancel}
92 106 onOk={form.submit}
93   - title={item.id ? "编辑待办时效" : "新增待办时效"}
  107 + title={item?.id ? "编辑待办时效" : "新增待办时效"}
94 108 confirmLoading={saveLoading}
95 109 >
96 110 <Form form={form} onFinish={handleSave} wrapperCol={{ span: 18 }} labelCol={{ span: 6 }}>
97   - {/* 待办名称 */}
98   - <Form.Item name="configIds" label="待办名称" rules={[{ required: true, message: "待办名称不能为空" }]}>
99   - <Select
100   - placeholder="请选择"
101   - showSearch
102   - mode={item.id ? undefined : "multiple"}
103   - optionFilterProp="children"
104   - filterOption={(input, option) => option?.children.indexOf(input) >= 0}
105   - >
106   - {todoList.map((item) => (
107   - <Select.Option value={item.id} key={item.id}>
108   - {item.itemName}
109   - </Select.Option>
110   - ))}
111   - </Select>
  111 + <Form.Item
  112 + name="applyType"
  113 + label="适用类型"
  114 + rules={[{ required: true, message: "适用类型不能为空" }]}
  115 + getValueFromEvent={({ target }) => {
  116 + setParams({ configId: item?.configId, applyType: target.value }, true);
  117 + if (!item?.id) {
  118 + form.setFieldsValue({ configIds: undefined });
  119 + }
  120 + return target.value;
  121 + }}
  122 + >
  123 + <RadioGroup>
  124 + <Radio value={ApplyType["全部门店"]}>全部门店</Radio>
  125 + <Radio value={ApplyType["部分门店"]}>部分门店</Radio>
  126 + </RadioGroup>
  127 + </Form.Item>
  128 + <Form.Item noStyle shouldUpdate={(prevValues, curValues) => prevValues.applyType != curValues.applyType}>
  129 + {({ getFieldValue }) => {
  130 + const _applyType = getFieldValue("applyType");
  131 + let domNode = null;
  132 + if (_applyType) {
  133 + domNode = (
  134 + <Form.Item name="configIds" label="待办" rules={[{ required: true, message: "待办名称不能为空" }]}>
  135 + <Select
  136 + placeholder="请选择"
  137 + showSearch
  138 + optionFilterProp="children"
  139 + labelInValue
  140 + filterOption={(input, option) => option?.children.indexOf(input) >= 0}
  141 + >
  142 + {todoList.map((item) => (
  143 + <Select.Option value={item.id} key={item.id}>
  144 + {item.itemName}
  145 + </Select.Option>
  146 + ))}
  147 + </Select>
  148 + </Form.Item>
  149 + );
  150 + }
  151 + if (ApplyType.部分门店 == _applyType) {
  152 + return (
  153 + <>
  154 + <Form.Item
  155 + name="applyShops"
  156 + label="适用门店"
  157 + rules={[{ required: true, message: "适用门店不能为空" }]}
  158 + >
  159 + <ShopSelectNew multiple />
  160 + </Form.Item>
  161 + {domNode}
  162 + </>
  163 + );
  164 + } else {
  165 + return domNode;
  166 + }
  167 + }}
112 168 </Form.Item>
113 169  
114 170 {/* 待办时效值 */}
... ...
src/pages/backlog/TaskTime/components/ShopModal.tsx 0 → 100644
  1 +import React, { useEffect } from "react";
  2 +import { Modal, Table } from "antd";
  3 +import { queryApplyShops } from "../api";
  4 +import useInitial from "@/hooks/useInitail";
  5 +
  6 +const Column = Table.Column;
  7 +
  8 +interface Props {
  9 + visible: boolean;
  10 + onCancel: () => void;
  11 + id?: number;
  12 +}
  13 +
  14 +export default ({ visible, onCancel, id }: Props) => {
  15 + const { data, setParams, loading, setData } = useInitial<any[], number | undefined>(queryApplyShops, [], id, !id);
  16 + useEffect(() => {
  17 + if (visible) {
  18 + setParams(id, true);
  19 + } else {
  20 + setData([]);
  21 + }
  22 + }, [visible]);
  23 +
  24 + return (
  25 + <Modal visible={visible} onCancel={onCancel} onOk={onCancel} title="适用门店">
  26 + <Table loading={loading} dataSource={data} rowKey={(record: any) => record.shopId}>
  27 + <Column title="门店id" width={80} dataIndex="shopId" align="center" />
  28 + <Column title="门店名称" dataIndex="shopName" align="center" />
  29 + </Table>
  30 + </Modal>
  31 + );
  32 +};
... ...
src/pages/backlog/TaskTime/index.tsx
1   -import React, { useState} from "react";
  1 +import React, { useState } from "react";