Commit 28f41719ed20868d229dad0ef95907ffc1f7f7cc

Authored by 谢忠泽
2 parents e7d90af6 50d3e44c

Merge branch 'master' into contract

Showing 68 changed files with 2110 additions and 248 deletions
config/routers/crm_new.ts
... ... @@ -82,7 +82,11 @@ export default [
82 82 component: './crm_new/Settings/subpages/CloseClue',
83 83 },
84 84 {
  85 + path: '/crm/clueConnect', // 线索有效接通配置
  86 + component: './crm_new/CluesConnectTargetEffectively',
  87 + },
  88 + {
85 89 path: '/crm/clueShareBrand', // 线索品牌共享分组
86 90 component: './crm_new/Settings/subpages/ClueBrandSharing',
87   - },
  91 + }
88 92 ];
89 93 \ No newline at end of file
... ...
config/routers/pms.ts
... ... @@ -163,4 +163,8 @@ export default [
163 163 path: '/pms/transfer/storageOverStock', // 可调出配件
164 164 component: './pms/transfer/StorageOverStock'
165 165 },
  166 + {
  167 + path: '/pms/transfer/huolalaSetting', // 货拉拉账户配置
  168 + component: './pms/transfer/HuolalaSetting'
  169 + },
166 170 ];
... ...
src/components/CarTableTreeAuth/SelectSpec.tsx 0 → 100644
  1 +import React, { useEffect, useState } from "react";
  2 +import {
  3 + Table,
  4 + Select,
  5 +} from "antd";
  6 +import {
  7 + CarOptionVo,
  8 +} from "@/pages/stock/Components/api";
  9 +import { ColumnsType } from 'antd/lib/table';
  10 +
  11 +interface Props {
  12 + onChange?: (pa: any) => void;
  13 + value?: any[];
  14 + disabled?: boolean;
  15 + specList?: CarOptionVo[]
  16 +}
  17 +
  18 +interface Item {
  19 + label: string;
  20 + value: number;
  21 + key?: number;
  22 +}
  23 +const { Column } = Table;
  24 +const { Option } = Select;
  25 +
  26 +const columns: ColumnsType<CarOptionVo> = [
  27 + {
  28 + title: '车型',
  29 + dataIndex: 'name',
  30 + },
  31 + {
  32 + title: '配置代码',
  33 + dataIndex: 'specConfigCodeList',
  34 + render: (t) => t.map((i: string, key: number) => (<div key={i}>{key + 1}.{i}</div>))
  35 + },
  36 +];
  37 +export default function index({ onChange: onSelected, value, disabled, specList = [] }: Props) {
  38 + const rowSelection = {
  39 + onChange: (selectedRowKeys: React.Key[], selectedRows: CarOptionVo[]) => {
  40 + onSelected && onSelected(selectedRows);
  41 + },
  42 + };
  43 +
  44 + return (
  45 + <>
  46 + <Table
  47 + rowSelection={{
  48 + type: "checkbox",
  49 + selectedRowKeys: value && value.map(item => item.id),
  50 + ...rowSelection,
  51 + }}
  52 + pagination={false}
  53 + // loading={}
  54 + rowKey="id"
  55 + size="small"
  56 + scroll={{ y: 500 }}
  57 + columns={columns}
  58 + dataSource={specList}
  59 + />
  60 + </>
  61 + );
  62 +}
... ...
src/components/CarTableTreeAuth/entity.ts 0 → 100644
  1 +export interface CarAuthList {
  2 + authType: number;
  3 + brandId: number;
  4 + brandName: number;
  5 + children?: Array<SeriesAuth>
  6 +}
  7 +
  8 +interface SeriesAuth {
  9 + authType: number;
  10 + seriesId: number;
  11 + seriesName: string;
  12 + children?: Array<SpecAuth>
  13 +}
  14 +interface SpecAuth {
  15 + authType: number;
  16 + specId: number;
  17 + specName: string;
  18 +}
0 19 \ No newline at end of file
... ...
src/components/CarTableTreeAuth/index.tsx 0 → 100644
  1 +import React, { useEffect, useState } from "react";
  2 +import {
  3 + Button,
  4 + Card,
  5 + Table,
  6 + Modal,
  7 + Form,
  8 + Select,
  9 + Space,
  10 + Spin,
  11 + message,
  12 +} from "antd";
  13 +import {
  14 + CarOptionVo,
  15 + getOnsaleSeriesApi,
  16 + getOnsaleSpecApi,
  17 +} from "@/pages/stock/Components/api";
  18 +import { PlusOutlined } from '@ant-design/icons';
  19 +import { ColumnsType } from 'antd/lib/table';
  20 +import SelectSpec from './SelectSpec';
  21 +import { CarAuthList } from './entity';
  22 +import { getBrandFilterApi } from '@/common/api';
  23 +
  24 +interface Props {
  25 + onChange?: (pa: any) => void;
  26 + value?: CarAuthList[];
  27 + disabled?: boolean;
  28 + brandList?: CommonApi.OptionVO[];
  29 + /**品牌是否多选,默认true */
  30 + brandMultiple?: boolean;
  31 +}
  32 +
  33 +interface Item {
  34 + label: string;
  35 + value: number;
  36 + key?: number;
  37 +}
  38 +const { Column } = Table;
  39 +const { Option } = Select;
  40 +
  41 +export default function index({ onChange, value, disabled, brandMultiple = true, brandList }: Props) {
  42 + const [form] = Form.useForm();
  43 + // 控制Modal是否可见
  44 + const [visible, setVisible] = useState<boolean>(false);
  45 + // 控制是否可见车型下拉框
  46 + const [level, setLevel] = useState<number>(1);
  47 + //存储表格当前车系
  48 + const [currentItem, setCurrentItem] = useState<any>();
  49 + const [brandData, setBrandData] = useState<CommonApi.OptionVO[]>([]);
  50 + //存储Modal中可选的车系
  51 + const [series, setSeries] = useState<any>([]);
  52 + //存储接口返回的车型
  53 + const [specList, setSpecList] = useState<any>([]);
  54 + //存储Modal选择的品牌和车系作为表格的数据源
  55 + const [savaData, setSavadata] = useState<any>([]);
  56 + // 存储已经选中的车系
  57 + const [selectedSeries, setSelectedSeries] = useState<any[]>([]);
  58 + const [fetchLoading, setFetchLoading] = useState(false);
  59 +
  60 + useEffect(() => {
  61 + if (value && value.length) {
  62 + setSelectedSeries([...value]);
  63 + setSavadata([...value]);
  64 + }
  65 + }, [value]);
  66 +
  67 + useEffect(() => {
  68 + if (brandList && Array.isArray(brandList)) {
  69 + setBrandData(brandList || []);
  70 + }
  71 + }, [brandList]);
  72 +
  73 + function getBrands() {
  74 + if (brandData.length) {
  75 + return;
  76 + }
  77 + setFetchLoading(true);
  78 + getBrandFilterApi().then(res => {
  79 + setBrandData(res.data || []);
  80 + setFetchLoading(false);
  81 + }).catch(err => {
  82 + message.error(err.message);
  83 + setFetchLoading(false);
  84 + });
  85 + }
  86 +
  87 + const _onOk = () => {
  88 + form
  89 + .validateFields()
  90 + .then((fileds) => {
  91 + if (level === 2) {
  92 + const { series } = fileds;
  93 + const _series = series.map((item: Item) => ({
  94 + seriesId: item.value,
  95 + seriesName: item.label,
  96 + authType: 1,
  97 + }));
  98 +
  99 + const currentSeries = (savaData.filter((i: any) => i.brandId === currentItem.brandId)[0] || {}).children || [];
  100 + /**判断已有数据保留 */
  101 + if (currentSeries.length) {
  102 + const selectedIds = currentSeries.map(i => i.seriesId);
  103 + let newAuthSeries: any[] = [];
  104 + _series.forEach((item: any) => {
  105 + if (selectedIds.includes(item.seriesId)) {
  106 + newAuthSeries = newAuthSeries.concat(currentSeries.filter((list: any) => list.seriesId === item.seriesId));
  107 + } else {
  108 + newAuthSeries.push(item);
  109 + }
  110 + });
  111 + currentItem.children = newAuthSeries;
  112 + } else {
  113 + currentItem.children = _series;
  114 + }
  115 +
  116 + const tempData = savaData.map((item: any) => (item.brandId === currentItem.brandId ? { ...currentItem, authType: series.length ? 2 : 1 } : { ...item, authType: 1 }));
  117 + setSavadata([...tempData]);
  118 + onChange && onChange(tempData);
  119 + setVisible(false);
  120 + return;
  121 + }
  122 + if (level === 3) {
  123 + const { spec } = fileds;
  124 + const _spec = spec.map((item: any) => ({
  125 + specId: item.id,
  126 + specName: item.name,
  127 + }));
  128 + currentItem.children = _spec;
  129 + currentItem.authType = 2;
  130 + const tempData = savaData.map((item: any) => {
  131 + if (item.children) {
  132 + const newChildren = item.children.map((i: any) => (i.seriesId === currentItem.seriesId ? { ...currentItem, authType: spec.length ? 2 : 1 } : i));
  133 + item.children = newChildren;
  134 + }
  135 + return { ...item, authType: 1 };
  136 + });
  137 + setSavadata([...tempData]);
  138 + onChange && onChange(tempData);
  139 + setVisible(false);
  140 + return;
  141 + }
  142 + const { brand } = fileds;
  143 + const tempArray = (brandMultiple ? brand : [brand]).map((item: any) => ({
  144 + brandName: item.label,
  145 + brandId: item.value,
  146 + authType: 1, //1全部2部分
  147 + }));
  148 + const selectedBrands: number[] = savaData.map((i: any) => i.brandId);
  149 + let newAuthCar: any[] = [];
  150 + tempArray.forEach((item: any) => {
  151 + if (selectedBrands.includes(item.brandId)) {
  152 + newAuthCar = newAuthCar.concat(savaData.filter(list => list.brandId === item.brandId));
  153 + } else {
  154 + newAuthCar.push(item);
  155 + }
  156 + });
  157 + setSavadata(newAuthCar);
  158 + onChange && onChange(newAuthCar);
  159 + setVisible(false);
  160 + })
  161 + .catch((err) => console.log(err.message));
  162 + };
  163 +
  164 + // 选择部分车辆表格==》删除车系
  165 + const onDelete = (record: any) => {
  166 + const _savaData = savaData.filter(
  167 + (item: any) => item.seriesId != record.seriesId
  168 + );
  169 + const _selectedSeries = selectedSeries.filter(
  170 + (item) => item.seriesId != record.seriesId
  171 + );
  172 + setSavadata([..._savaData]);
  173 + onChange && onChange(_savaData);
  174 + setSelectedSeries([..._selectedSeries]);
  175 + };
  176 +
  177 + // 选择部分车辆表格==》编辑选择部分车系、车型
  178 + const onSelectSpec = async (record: any) => {
  179 + setCurrentItem(record);
  180 + setVisible(true);
  181 + if (record.brandId) {
  182 + setLevel(2);
  183 + setFetchLoading(true);
  184 + try {
  185 + const { data } = await getOnsaleSeriesApi(record.brandId);
  186 + const selectedSeries = savaData.filter((brand: any) => brand.brandId === record.brandId)[0].children;
  187 + selectedSeries && form.setFieldValue("series", selectedSeries.map(i => ({ value: i.seriesId, label: i.seriesName })));
  188 + setSeries(data);
  189 + setFetchLoading(false);
  190 + } catch (err: any) {
  191 + message.error(err.message);
  192 + setFetchLoading(false);
  193 + }
  194 + }
  195 + if (record.seriesId) {
  196 + setLevel(3);
  197 + setFetchLoading(true);
  198 + try {
  199 + const { data } = await getOnsaleSpecApi(record.seriesId);
  200 + record.children && form.setFieldValue("spec", record.children.map(i => ({ id: i.specId, name: i.specName })));
  201 + setSpecList(data);
  202 + setFetchLoading(false);
  203 + } catch (err: any) {
  204 + message.error(err.message);
  205 + setFetchLoading(false);
  206 + }
  207 + }
  208 + };
  209 +
  210 + return (
  211 + <>
  212 + <Card>
  213 + {!disabled && (
  214 + <div style={{ display: "flex", justifyContent: "flex-end" }}>
  215 + <Button
  216 + type="link"
  217 + disabled={disabled}
  218 + icon={<PlusOutlined />}
  219 + onClick={() => {
  220 + getBrands();
  221 + setVisible(true);
  222 + setLevel(1);
  223 + savaData.length && form.setFieldValue("brand", savaData.map((i: any) => ({ value: i.brandId, label: i.brandName })));
  224 + // form.resetFields();
  225 + }}
  226 + >
  227 + 新增
  228 + </Button>
  229 + </div>
  230 + )}
  231 +
  232 + <Table
  233 + dataSource={value}
  234 + rowKey={(record) => String(record.brandId || record.seriesId || record.specId)}
  235 + >
  236 + <Column
  237 + title="品牌"
  238 + dataIndex="brandName"
  239 + key="brandId"
  240 + />
  241 + <Column
  242 + title="车系"
  243 + dataIndex="seriesName"
  244 + key="seriesId"
  245 + render={(text, record: any) => {
  246 + return (text || record.specName || (record.children && record.children.length !== 0) ? (
  247 + <span>
  248 + {text}
  249 + </span>
  250 + ) : (
  251 + <span style={{ color: "#999" }}>全部车系</span>
  252 + ));
  253 + }}
  254 + />
  255 + <Column
  256 + title="车型"
  257 + dataIndex="specName"
  258 + key="specId"
  259 + render={(text, record: any) => {
  260 + return (text || (record.children && record.children.length !== 0) ? (
  261 + <span>
  262 + {text}
  263 + </span>
  264 + ) : (
  265 + <span style={{ color: "#999" }}>全部车型</span>
  266 + ));
  267 + }}
  268 + />
  269 + {!disabled && (
  270 + <Column
  271 + title="操作"
  272 + render={(_, record: any, index) => {
  273 + return (
  274 + <Space>
  275 + <Button
  276 + type={record.brandId ? "primary" : "link"}
  277 + style={{ padding: 2 }}
  278 + onClick={() => onSelectSpec(record)}
  279 + disabled={disabled}
  280 + >
  281 + {record.brandId ? "编辑车系" : (record.seriesId ? "编辑车型" : "")}
  282 + </Button>
  283 + {/* <Popconfirm
  284 + title="确定删除?"
  285 + okText="确定"
  286 + style={{ padding: 0 }}
  287 + cancelText="取消"
  288 + onConfirm={() => onDelete(record)}
  289 + >
  290 + <Button type="link" danger disabled={disabled}>
  291 + 删除
  292 + </Button>
  293 + </Popconfirm> */}
  294 + </Space>
  295 + );
  296 + }}
  297 + />
  298 + )}
  299 + </Table>
  300 + </Card>
  301 +
  302 + {/* 选择品牌和车系 */}
  303 + <Modal
  304 + title="选择车辆信息"
  305 + visible={visible}
  306 + onOk={() => form.submit()}
  307 + onCancel={() => {
  308 + setVisible(false);
  309 + }}
  310 + maskClosable={false}
  311 + afterClose={() => {
  312 + form.resetFields();
  313 + setCurrentItem({});
  314 + }}
  315 + >
  316 + <Spin spinning={fetchLoading}>
  317 + <Form onFinish={_onOk} form={form}>
  318 + {level === 1 ? (
  319 + <Form.Item
  320 + label="品牌"
  321 + name="brand"
  322 + >
  323 + <Select
  324 + labelInValue
  325 + mode={brandMultiple ? "multiple" : undefined}
  326 + placeholder="选择品牌"
  327 + >
  328 + {brandData.map((item) => (
  329 + <Option value={item.id} key={item.id}>
  330 + {item.name}
  331 + </Option>
  332 + ))}
  333 + </Select>
  334 + </Form.Item>
  335 + ) : null}
  336 +
  337 + {/* 车系 */}
  338 + {level === 2 && (
  339 + <Form.Item
  340 + label="车系"
  341 + name="series"
  342 + // rules={[{ required: true, message: "请选择车系" }]}
  343 + >
  344 + <Select labelInValue mode="multiple" placeholder="选择车系" allowClear>
  345 + {series.map((item: any) => (
  346 + <Option value={item.id} key={item.id}>
  347 + {item.name}
  348 + </Option>
  349 + ))}
  350 + </Select>
  351 + </Form.Item>
  352 + )}
  353 + {level === 3 ? (
  354 + <Form.Item
  355 + label=""
  356 + name="spec"
  357 + >
  358 + {/* <Select labelInValue mode="multiple" placeholder="选择车型" allowClear>
  359 + {specList.map((item: any) => (
  360 + <Option value={item.id} key={item.id}>
  361 + {item.name}
  362 + </Option>
  363 + ))}
  364 + </Select> */}
  365 + <SelectSpec specList={specList} />
  366 + </Form.Item>
  367 + ) : null}
  368 + </Form>
  369 + </Spin>
  370 + </Modal>
  371 + </>
  372 + );
  373 +}
... ...
src/pages/attendance/Attend/subpages/AttendanceGroup/api.ts
1   -import { http,PromisePageResp } from "@/typing/http";
  1 +import { http, PromisePageResp } from "@/typing/http";
2 2 import request from "@/utils/request";
3 3 import { ATTENDANCE_HOST } from "@/utils/host";
4 4  
... ... @@ -70,10 +70,15 @@ export function saveApi(params?: Item): P&lt;void&gt; {
70 70 }
71 71  
72 72 interface BaseSettingItem {
73   - id?: number;
74   - noticeTime?: number; //待办提前通知时间(分钟)
75   - defectTime?: number; //严重迟到时间判定(分钟)
76   - lackTime?: number; //缺卡判定时间
  73 + id?: number; // 主键
  74 + groupId?: number; // 集团id
  75 + defectTime?: number; // 严重迟到时间判定(分钟)
  76 + onDutyNoticeTime?: number; // 上班待办提前通知时间(分钟)
  77 + offDutyNoticeTime?: number; // 下班待办延后通知时间(分钟)
  78 + onDutyLackTime?: number; // 上班缺卡时间判定(分钟)
  79 + offDutyLackTime?: number; // 下班缺卡时间判定(分钟)
  80 + outsideRemainingHour?: number; // 外勤结束时间离门店下班时间≤?小时不用打考勤卡
  81 + travelRemainingHour?: number; // 出差结束时间离门店下班时间≤?小时不用打考勤卡
77 82 }
78 83 /**获取考勤组基础设置
79 84 * /attendance/base/setting/get
... ...
src/pages/attendance/Attend/subpages/AttendanceGroup/components/TimeConfig.tsx
1   -import { Button, Form, InputNumber, message, Popconfirm, Radio, Row, Select } from "antd";
  1 +import { Button, Form, InputNumber, message, Popconfirm, Row } from "antd";
2 2 import React, { useEffect, useState } from "react";
3 3 import useInitial from "@/hooks/useInitail";
4   -import { fetchBaseSettingApi, saveOrUpdateApi } from "@/pages/attendance/Attend/subpages/AttendanceGroup/api";
  4 +import {
  5 + fetchBaseSettingApi,
  6 + saveOrUpdateApi,
  7 +} from "@/pages/attendance/Attend/subpages/AttendanceGroup/api";
5 8  
6 9 const FormItem = Form.Item;
7 10  
... ... @@ -49,7 +52,12 @@ export default function TimeConfig() {
49 52  
50 53 return (
51 54 <div>
52   - <Form form={form} onFinish={submit} labelCol={{ span: 6 }} wrapperCol={{ span: 15 }}>
  55 + <Form
  56 + form={form}
  57 + onFinish={submit}
  58 + labelCol={{ span: 6 }}
  59 + wrapperCol={{ span: 15 }}
  60 + >
53 61 <div
54 62 style={{
55 63 display: "flex",
... ... @@ -77,7 +85,8 @@ export default function TimeConfig() {
77 85 />
78 86 </FormItem>
79 87 <span style={{ marginLeft: 5 }}>
80   - 到应打卡时间 <span style={{ color: "#999999" }}>(除最后一次应打卡)</span>
  88 + 到应打卡时间{" "}
  89 + <span style={{ color: "#999999" }}>(除最后一次应打卡)</span>
81 90 </span>
82 91 </div>
83 92 </div>
... ... @@ -93,7 +102,10 @@ export default function TimeConfig() {
93 102 >
94 103 <span style={{ color: "#ff4d4f" }}>*</span> 最后一次应打卡时间要求:
95 104 <div>
96   - <span style={{ marginRight: 5, marginLeft: 5 }}> 应打卡时间延后</span>
  105 + <span style={{ marginRight: 5, marginLeft: 5 }}>
  106 + {" "}
  107 + 应打卡时间延后
  108 + </span>
97 109 <FormItem
98 110 name="offDutyNoticeTime"
99 111 label="打卡时间要求"
... ... @@ -108,7 +120,9 @@ export default function TimeConfig() {
108 120 disabled={!edit}
109 121 />
110 122 </FormItem>
111   - <span style={{ color: "#999999", marginLeft: 5 }}>(当天仅一次打卡不计此情况)</span>
  123 + <span style={{ color: "#999999", marginLeft: 5 }}>
  124 + (当天仅一次打卡不计此情况)
  125 + </span>
112 126 </div>
113 127 </div>
114 128  
... ... @@ -123,9 +137,17 @@ export default function TimeConfig() {
123 137 >
124 138 <span style={{ color: "#ff4d4f" }}>*</span> 严重迟到判定:
125 139 <div>
126   - <span style={{ marginLeft: 5, marginRight: 5 }}>在应打卡时间延后</span>
  140 + <span style={{ marginLeft: 5, marginRight: 5 }}>
  141 + 在应打卡时间延后
  142 + </span>
127 143  
128   - <FormItem name="defectTime" noStyle rules={[{ required: true, message: "请填写严重迟到时间判定(分钟)" }]}>
  144 + <FormItem
  145 + name="defectTime"
  146 + noStyle
  147 + rules={[
  148 + { required: true, message: "请填写严重迟到时间判定(分钟)" },
  149 + ]}
  150 + >
129 151 <InputNumber
130 152 min={0}
131 153 style={{ width: 200 }}
... ... @@ -147,7 +169,10 @@ export default function TimeConfig() {
147 169 >
148 170 <span style={{ color: "#ff4d4f" }}>*</span> 上班缺卡时间判定:
149 171 <div>
150   - <span style={{ marginRight: 5, marginLeft: 5 }}> 应打卡时间延后</span>
  172 + <span style={{ marginRight: 5, marginLeft: 5 }}>
  173 + {" "}
  174 + 应打卡时间延后
  175 + </span>
151 176 <FormItem
152 177 name="onDutyLackTime"
153 178 label="打卡时间要求"
... ... @@ -175,8 +200,14 @@ export default function TimeConfig() {
175 200 >
176 201 <span style={{ color: "#ff4d4f" }}>*</span> 下班缺卡时间判定:
177 202 <div>
178   - <span style={{ marginRight: 5, marginLeft: 5 }}>在应打卡时间延后</span>
179   - <FormItem name="offDutyLackTime" noStyle rules={[{ required: true, message: "请填写缺卡时间判定(分钟)" }]}>
  203 + <span style={{ marginRight: 5, marginLeft: 5 }}>
  204 + 在应打卡时间延后
  205 + </span>
  206 + <FormItem
  207 + name="offDutyLackTime"
  208 + noStyle
  209 + rules={[{ required: true, message: "请填写缺卡时间判定(分钟)" }]}
  210 + >
180 211 <InputNumber
181 212 min={0}
182 213 style={{ width: 200 }}
... ... @@ -188,6 +219,66 @@ export default function TimeConfig() {
188 219 <span style={{ marginLeft: 5 }}>后不允许打卡</span>
189 220 </div>
190 221 </div>
  222 + <div
  223 + style={{
  224 + display: "flex",
  225 + justifyContent: "flex-start",
  226 + alignItems: "center",
  227 + marginTop: 20,
  228 + paddingLeft: "20%",
  229 + }}
  230 + >
  231 + <span style={{ color: "#ff4d4f" }}>*</span> 外勤结束时间:
  232 + <div>
  233 + <span style={{ marginLeft: 5, marginRight: 5 }}>
  234 + 离门店下班时间提前
  235 + </span>
  236 + <FormItem
  237 + name="outsideRemainingHour"
  238 + noStyle
  239 + rules={[{ required: true, message: "请填写打卡时间要求" }]}
  240 + >
  241 + <InputNumber
  242 + min={0}
  243 + style={{ width: 200 }}
  244 + formatter={(value) => `${value}小时`}
  245 + parser={(value: any) => value.replace("小时", "")}
  246 + disabled={!edit}
  247 + />
  248 + </FormItem>
  249 + <span style={{ marginLeft: 5, marginRight: 5 }}>不用考勤打卡</span>
  250 + </div>
  251 + </div>
  252 + <div
  253 + style={{
  254 + display: "flex",
  255 + justifyContent: "flex-start",
  256 + alignItems: "center",
  257 + marginTop: 20,
  258 + paddingLeft: "20%",
  259 + }}
  260 + >
  261 + <span style={{ color: "#ff4d4f" }}>*</span> 出差结束时间:
  262 + <div>
  263 + <span style={{ marginLeft: 5, marginRight: 5 }}>
  264 + 离门店下班时间提前
  265 + </span>
  266 + <FormItem
  267 + name="travelRemainingHour"
  268 + noStyle
  269 + rules={[{ required: true, message: "请填写打卡时间要求" }]}
  270 + >
  271 + <InputNumber
  272 + min={0}
  273 + style={{ width: 200 }}
  274 + formatter={(value) => `${value}小时`}
  275 + parser={(value: any) => value.replace("小时", "")}
  276 + disabled={!edit}
  277 + />
  278 + </FormItem>
  279 + <span style={{ marginLeft: 5, marginRight: 5 }}>不用考勤打卡</span>
  280 + </div>
  281 + </div>
191 282 </Form>
192 283 <Row style={{ width: "80%", marginTop: 20 }} justify="center">
193 284 {!edit ? (
... ... @@ -196,7 +287,11 @@ export default function TimeConfig() {
196 287 </Button>
197 288 ) : (
198 289 <div>
199   - <Button type="primary" onClick={form.submit} loading={confirmLoading}>
  290 + <Button
  291 + type="primary"
  292 + onClick={form.submit}
  293 + loading={confirmLoading}
  294 + >
200 295 确定
201 296 </Button>
202 297 <Popconfirm
... ...
src/pages/attendance/Leave/components/Modal.tsx
... ... @@ -22,8 +22,9 @@ const CreateModal = (props: Props) =&gt; {
22 22 useEffect(() => {
23 23 if (visiable && type === 1) {
24 24 API.fetchDetail(1).then((res: any) => {
25   - setYear(res.data);
26   - setYearData(res.data.conditions);
  25 + const data = res.data || {};
  26 + setYear(data);
  27 + setYearData(data.conditions);
27 28 });
28 29 }
29 30 }, [visiable]);
... ... @@ -91,7 +92,7 @@ const CreateModal = (props: Props) =&gt; {
91 92 rules={[{ required: !(type === 1 || type === 8 || type === 6) }]}
92 93 hidden={type === 1 || type === 8 || type === 6 || type === 10}
93 94 >
94   - <InputNumber min={1} style={{ width: 200 }} />
  95 + <InputNumber min={1} style={{ width: 200 }} addonAfter="天" />
95 96 </FormItem>
96 97 <FormItem
97 98 name="annualWay"
... ... @@ -110,7 +111,7 @@ const CreateModal = (props: Props) =&gt; {
110 111 rules={[{ required: type === 1 }]}
111 112 hidden={!(type === 1)}
112 113 >
113   - <InputNumber min={1} style={{ width: 200 }} />
  114 + <InputNumber min={1} style={{ width: 200 }} addonAfter="天" />
114 115 </FormItem>
115 116 <FormItem
116 117 name="advanceDays"
... ... @@ -127,7 +128,7 @@ const CreateModal = (props: Props) =&gt; {
127 128 ]}
128 129 hidden={type === 3 || type === 8 || type === 5 || type === 10}
129 130 >
130   - <InputNumber min={1} style={{ width: 200 }} />
  131 + <InputNumber min={1} style={{ width: 200 }} addonAfter="天" />
131 132 </FormItem>
132 133 <FormItem
133 134 name="times"
... ... @@ -135,7 +136,7 @@ const CreateModal = (props: Props) =&gt; {
135 136 rules={[{ required: type === 6 || type === 8 }]}
136 137 hidden={!(type === 6 || type === 8)}
137 138 >
138   - <InputNumber min={1} style={{ width: 200 }} />
  139 + <InputNumber min={1} style={{ width: 200 }} addonAfter="次" />
139 140 </FormItem>
140 141 <FormItem
141 142 name="conditions"
... ...
src/pages/attendance/Leave/index.tsx
1   -import React, { useState } from 'react';
  1 +import React, { useState } from "react";
2 2 import { PageHeaderWrapper } from "@ant-design/pro-layout";
3   -import { Button, Card, Table } from 'antd';
4   -import * as TYPE from './entity';
5   -import Modal from './components/Modal';
6   -import useInitial from '@/hooks/useInitail';
7   -import * as API from './api';
  3 +import { Button, Card, Table } from "antd";
  4 +import * as TYPE from "./entity";
  5 +import Modal from "./components/Modal";
  6 +import useInitial from "@/hooks/useInitail";
  7 +import * as API from "./api";
8 8  
9 9 const Column = Table.Column;
10 10  
... ... @@ -13,7 +13,7 @@ const Leave = () =&gt; {
13 13 const [type, setType] = useState<number>(0);
14 14 const { data, setParams } = useInitial(API.fetchDetail, {}, type);
15 15  
16   - const onEdit = (record:any) => {
  16 + const onEdit = (record: any) => {
17 17 setParams(record.type, true);
18 18 setType(record.type);
19 19 setVisiable(true);
... ... @@ -40,10 +40,10 @@ const Leave = () =&gt; {
40 40 visiable={visiable}
41 41 setVisiable={setVisiable}
42 42 type={type}
43   - data={data}
  43 + data={data || {}}
44 44 />
45 45 </PageHeaderWrapper>
46 46 );
47 47 };
48 48  
49   -export default Leave;
50 49 \ No newline at end of file
  50 +export default Leave;
... ...
src/pages/crm_new/CluesConnectTargetEffectively/api.ts 0 → 100644
  1 +import request from '@/utils/request';
  2 +import { CRM_HOST } from '@/utils/host';
  3 +
  4 +interface RequestParams {
  5 + keywords?: string
  6 +}
  7 +
  8 +export interface Result {
  9 + id?: number // 配置id
  10 + dialAims?: number // 线索接通目标
  11 + displayName?: string // 显示名称
  12 + shopList?: ShopList[] // 门店列表
  13 +}
  14 +
  15 +export interface ShopList {
  16 + shopId?: number // 门店id
  17 + shopName?: string // 门店名称
  18 +}
  19 +
  20 +/** 查询线索拨通目标配置列表 */
  21 +export function getConfigApi(params: RequestParams) {
  22 + return request.get<Result[]>(`${CRM_HOST}/erp/clue/dial/aims/config/list`, {params});
  23 +}
  24 +
  25 +/** 查询线索拨通目标已配置的门店 */
  26 +export function getHaveShopListApi() {
  27 + return request.get<number[]>(`${CRM_HOST}/erp/clue/dial/aims/config/already/exists/shopIds`);
  28 +}
  29 +
  30 +/** 保存线索拨通目标配置 */
  31 +export function saveConfigApi(params: Result) {
  32 + return request.post<Result>(`${CRM_HOST}/erp/clue/dial/aims/config/save`, params);
  33 +}
  34 +
  35 +/** 删除线索拨通目标配置 */
  36 +export function deleteConfigApi(id?: number) {
  37 + return request.post<Result>(`${CRM_HOST}/erp/clue/dial/aims/config/delete`, {id}, {contentType: 'form-urlencoded'});
  38 +}
0 39 \ No newline at end of file
... ...
src/pages/crm_new/CluesConnectTargetEffectively/components/EditModal.tsx 0 → 100644
  1 +import React, { useState, useEffect } from 'react';
  2 +import { Button, Form, message, InputNumber, Select, Modal} from 'antd';
  3 +import ShopSelectNew from '@/components/ShopSelectNew';
  4 +import { useStore } from '../index';
  5 +import { saveConfigApi, getHaveShopListApi } from '../api';
  6 +import { debounce } from 'lodash';
  7 +
  8 +const Option = Select.Option;
  9 +
  10 +export default function Index() {
  11 + const [form] = Form.useForm();
  12 + const { current, setCurrent, setLoading } = useStore();
  13 + const [confirm, setConfirm] = useState<boolean>(false);
  14 + const [disabledShopIds, setDisabledShopIds] = useState<number[]>([]);
  15 +
  16 + useEffect(() => {
  17 + if (current.visible && current.data.id) {
  18 + handleSetValue();
  19 + const shopList = current.data.shopList || [];
  20 + getHaveShopListApi()
  21 + .then(res => {
  22 + const shopIdList = res.data || [];
  23 + const _shopIds = shopList.map(v => v.shopId) || [];
  24 + const disabledShop = shopIdList.filter(v => !(_shopIds.includes(v))) || [];
  25 + setDisabledShopIds(disabledShop);
  26 + })
  27 + .catch(e => {
  28 + message.error(e.message);
  29 + });
  30 + } else {
  31 + getHaveShopListApi()
  32 + .then(res => {
  33 + const shopIdList = res.data || [];
  34 + setDisabledShopIds(shopIdList);
  35 + })
  36 + .catch(e => {
  37 + message.error(e.message);
  38 + });
  39 + }
  40 + }, [current.visible]);
  41 +
  42 + function handleCancle() {
  43 + setCurrent({visible: false, data: {}});
  44 + }
  45 +
  46 + async function handleSubmit() {
  47 + const params = await form.validateFields();
  48 + setConfirm(true);
  49 + const _params = {
  50 + id: current.data?.id,
  51 + dialAims: params.dialAims,
  52 + shopList: params.shopList?.map((v: any) => ({shopId: v.value, shopName: v.label}))
  53 + };
  54 + saveConfigApi(_params)
  55 + .then(res => {
  56 + message.success(res.result);
  57 + setConfirm(false);
  58 + setCurrent({visible: false, data: {}});
  59 + setLoading(true);
  60 + })
  61 + .catch(e => {
  62 + message.error(e.message);
  63 + setConfirm(false);
  64 + });
  65 + }
  66 +
  67 + function handleSetValue() {
  68 + form.setFieldsValue({
  69 + dialAims: current.data.dialAims,
  70 + shopList: current.data.shopList?.map((v: any) => ({label: v.shopName, value: v.shopId}))
  71 + });
  72 + }
  73 +
  74 + function handleResetValue() {
  75 + form.setFieldsValue({shopList: [], dialAims: undefined});
  76 + }
  77 + return (
  78 + <Modal
  79 + title={current.data.id ? "编辑" : "新增"}
  80 + destroyOnClose
  81 + visible={current.visible}
  82 + maskClosable={false}
  83 + onCancel={handleCancle}
  84 + afterClose={() => handleResetValue()}
  85 + width="60%"
  86 + footer={[
  87 + <Button key="cancel" disabled={confirm} onClick={handleCancle} style={{marginLeft: 10}}>取消</Button>,
  88 + <Button key="submit" disabled={confirm} onClick={debounce(handleSubmit, 380)} type="primary" htmlType="submit" loading={confirm}>确认</Button>
  89 + ]}
  90 + >
  91 + <Form
  92 + form={form}
  93 + labelCol={{ span: 8 }}
  94 + wrapperCol={{ span: 10 }}
  95 + >
  96 +
  97 + <Form.Item
  98 + label="线索有效接通目标"
  99 + name="dialAims"
  100 + rules={[{ required: true, message: "请输入" }]}
  101 + >
  102 + <InputNumber
  103 + style={{width: '100%'}}
  104 + controls={false}
  105 + min={0}
  106 + formatter={value => `${value}条/天`}
  107 + precision={0}
  108 + parser={value => value?.replace('条/天', '')}
  109 + />
  110 + </Form.Item>
  111 + <Form.Item
  112 + label="适用门店"
  113 + name="shopList"
  114 + rules={[{ required: true, message: "请选择门店" }]}
  115 + labelAlign="right"
  116 + >
  117 + <ShopSelectNew disabledShopIds={disabledShopIds} defaultOptions={{bizTypes: "1"}} placeholder="请选择门店" multiple />
  118 + </Form.Item>
  119 +
  120 + </Form>
  121 +
  122 + </Modal>
  123 + );
  124 +}
0 125 \ No newline at end of file
... ...
src/pages/crm_new/CluesConnectTargetEffectively/components/List.tsx 0 → 100644
  1 +import React from "react";
  2 +import { message, Popconfirm, Table, Space } from "antd";
  3 +import { useStore } from '../index';
  4 +import {deleteConfigApi, Result } from '../api';
  5 +
  6 +const Column = Table.Column;
  7 +
  8 +export default function TableList() {
  9 + const {data, loading, setLoading, setShopData, setCurrent } = useStore();
  10 +
  11 + function handleDelete(id?: number) {
  12 + deleteConfigApi(id)
  13 + .then(res => {
  14 + message.success(res.result);
  15 + setLoading(true);
  16 + })
  17 + .catch(e => {
  18 + message.error(e.message);
  19 + });
  20 + }
  21 +
  22 + return (
  23 + <div>
  24 + <Table
  25 + dataSource={data}
  26 + pagination={false}
  27 + loading={loading}
  28 + rowKey="id"
  29 + >
  30 + <Column
  31 + title="上班期间线索有效接通目标(条/天)"
  32 + align="left"
  33 + dataIndex="dialAims"
  34 + />
  35 + <Column
  36 + title="适用门店"
  37 + align="left"
  38 + dataIndex="displayName"
  39 + render={(_text: string, record: Result) => <span style={{color: "#4189FD"}} onClick={() => setShopData({visible: true, data: record.shopList || []})}>{_text}</span>}
  40 + />
  41 + <Column
  42 + title="操作"
  43 + align="left"
  44 + render={(_text, record: Result) => {
  45 + return (
  46 + <Space>
  47 + <a onClick={() => setCurrent({visible: true, data: record})} style={{ display: "block", color: "#4189FD" }}>编辑</a>
  48 + <Popconfirm
  49 + title="是否删除?"
  50 + okText="确定"
  51 + cancelText="取消"
  52 + onConfirm={() => handleDelete(record.id)}
  53 + >
  54 + <a style={{color: "#EC3F2F"}}>删除</a>
  55 + </Popconfirm>
  56 + </Space>
  57 + );
  58 + }}
  59 + />
  60 + </Table>
  61 + </div>
  62 + );
  63 +}
... ...
src/pages/crm_new/CluesConnectTargetEffectively/components/ShopModal.tsx 0 → 100644
  1 +import React, {useEffect, useState} from 'react';
  2 +import {Modal, Button, List} from 'antd';
  3 +import { useStore } from '../index';
  4 +
  5 +export default function Index() {
  6 + const {shopData, setShopData } = useStore();
  7 +
  8 + function handleCancel() {
  9 + setShopData({visible: false, data: []});
  10 + }
  11 +
  12 + return (
  13 + <Modal
  14 + destroyOnClose
  15 + title="适用门店"
  16 + visible={shopData.visible}
  17 + maskClosable={false}
  18 + onCancel={handleCancel}
  19 + footer={[]}
  20 + >
  21 + <List
  22 + size="large"
  23 + style={{height: '300px', overflow: 'scroll'}}
  24 + dataSource={shopData?.data || []}
  25 + renderItem={(item: any) => <List.Item style={{justifyContent: 'center'}}>{item.shopName}</List.Item>}
  26 + />
  27 + <div
  28 + style={{
  29 + textAlign: 'center',
  30 + marginTop: 12,
  31 + height: 32,
  32 + lineHeight: '32px',
  33 + }}
  34 + ><Button type="primary" onClick={handleCancel}>返回</Button>
  35 + </div>
  36 + </Modal>
  37 + );
  38 +}
0 39 \ No newline at end of file
... ...
src/pages/crm_new/CluesConnectTargetEffectively/index.tsx 0 → 100644
  1 +import React, {useState} from 'react';
  2 +import { Card, Button, Row, Col } from 'antd';
  3 +import { PageHeaderWrapper } from '@ant-design/pro-layout';
  4 +import { createStore } from '@/hooks/moz';
  5 +import store from './store';
  6 +import List from './components/List';
  7 +import EditModal from './components/EditModal';
  8 +import ShopModal from './components/ShopModal';
  9 +import ShopSelectNew from '@/components/ShopSelectNew';
  10 +
  11 +export const { Provider, useStore } = createStore(store);
  12 +
  13 +function Index() {
  14 + const { setParams, setCurrent } = useStore();
  15 + const [selected, setSelected] = useState<any>([]);
  16 +
  17 + function handleOnChange(value: any) {
  18 + setParams({keywords: value[0]?.label || undefined}, true);
  19 + setSelected(value || []);
  20 + }
  21 + return (
  22 + <PageHeaderWrapper title={<Row align="middle"><span style={{width: "5px", height: "20px", backgroundColor: "#448EF7", borderRadius: "3px", display: 'inline-block', marginRight: "10px"}} /><span>线索有效接通目标配置</span></Row>}>
  23 + <Card>
  24 + <Row justify="space-between" style={{ marginBottom: 20 }}>
  25 + <Col span={10}>
  26 + <ShopSelectNew value={selected} onChange={handleOnChange} defaultOptions={{bizTypes: "1"}} placeholder="请选择门店" />
  27 + </Col>
  28 + <Button onClick={() => setCurrent({visible: true, data: {}})} type="primary">新增</Button>
  29 + </Row>
  30 + <List />
  31 + <EditModal />
  32 + <ShopModal />
  33 + </Card>
  34 + </PageHeaderWrapper>
  35 + );
  36 +}
  37 +
  38 +export default () => <Provider><Index /></Provider>;
... ...
src/pages/crm_new/CluesConnectTargetEffectively/store.ts 0 → 100644
  1 +import React, { useState } from 'react';
  2 +import useInitial from '@/hooks/useInitail';
  3 +import {getConfigApi, Result, ShopList} from './api';
  4 +
  5 +interface Current {
  6 + visible: boolean
  7 + data: Result
  8 +}
  9 +
  10 +interface ShopData {
  11 + visible: boolean
  12 + data: ShopList[]
  13 +}
  14 +
  15 +export default function useStore() {
  16 + const { data, loading, errMsg, setLoading, setParams, params } = useInitial(getConfigApi, [], {});
  17 + const [current, setCurrent] = useState<Current>({visible: false, data: {}});
  18 + const [shopData, setShopData] = useState<ShopData>({visible: false, data: []});
  19 + return {
  20 + data,
  21 + loading,
  22 + errMsg,
  23 + setLoading,
  24 + setParams,
  25 + params,
  26 + current,
  27 + setCurrent,
  28 + shopData,
  29 + setShopData
  30 + };
  31 +}
0 32 \ No newline at end of file
... ...
src/pages/finance/FinanceInvestor/components/ApitalModal.tsx
... ... @@ -39,7 +39,7 @@ export default function CreateModal() {
39 39 };
40 40 saveApitalAccountApi(params)
41 41 .then((res) => {
42   - message.success("保存成功");
  42 + message.success(res.result || "保存成功");
43 43 triggerModal();
44 44 setSaveLoading(false);
45 45 setLoading(true);
... ... @@ -53,7 +53,7 @@ export default function CreateModal() {
53 53 return (
54 54 <Modal
55 55 title={`${visiData.row.id ? "编辑" : "新增"}投资主体`}
56   - visible={visiData.visible}
  56 + open={visiData.visible}
57 57 onOk={form.submit}
58 58 onCancel={() => triggerModal()}
59 59 maskClosable={false}
... ... @@ -79,7 +79,7 @@ export default function CreateModal() {
79 79 </Select>
80 80 </FormItem>
81 81 <FormItem name="name" label="投资主体" rules={[{ required: true, message: "请填入投资主体" }]}>
82   - <Input placeholder="请填入财务主体" />
  82 + <Input placeholder="请填入投资主体" />
83 83 </FormItem>
84 84 <FormItem name="includeDealers" label="商家" rules={[{ required: true, message: "请选择商家" }]}>
85 85 <Select
... ...
src/pages/finance/SpecialAccount/FinancingCompany/components/CreateModal.tsx
... ... @@ -10,7 +10,8 @@ const FormItem = Form.Item;
10 10 const { Option } = Select;
11 11  
12 12 export default function CreateModal() {
13   - const { visible, current, setCurrent, setVisible, fcList, accountList, setLoading, dealerId, brandList } = useStore();
  13 + const { visible, current, setCurrent, setVisible, fcList, accountList, setLoading, dealerId, brandList, type } =
  14 + useStore();
14 15 const [form] = Form.useForm();
15 16  
16 17 const [saveLoading, setSaveLoading] = useState<boolean>(false);
... ... @@ -76,6 +77,10 @@ export default function CreateModal() {
76 77 }
77 78  
78 79 function submit(fieldValue: any) {
  80 + if (fieldValue.depositAccount.value === fieldValue.account.value) {
  81 + message.error("还款保证金账户、一般账户请勿配置为同一账户", 1.5);
  82 + return;
  83 + }
79 84 const param = {
80 85 dealerId,
81 86 ...fieldValue,
... ... @@ -155,7 +160,7 @@ export default function CreateModal() {
155 160 {({ getFieldValue }): any => {
156 161 const category = getFieldValue("compCategory");
157 162 return category ? (
158   - <FormItem label="融资公司" name="fcComp" rules={[{ required: true, message: "请选择融资公司" }]}>
  163 + <FormItem label="往来银行" name="fcComp" rules={[{ required: true, message: "请选择往来银行" }]}>
159 164 <Select
160 165 showSearch
161 166 labelInValue
... ... @@ -185,7 +190,7 @@ export default function CreateModal() {
185 190 <Radio value={2}>每张票支付</Radio>
186 191 </Radio.Group>
187 192 </FormItem>
188   - <FormItem name="depositAccount" label="保证金账户">
  193 + <FormItem name="depositAccount" label="还款保证金账户">
189 194 <Select labelInValue placeholder="请选择账户" showSearch optionFilterProp="children" allowClear>
190 195 {accountList.map((item) => (
191 196 <Option key={item.id} value={item.id}>
... ...
src/pages/finance/SpecialAccount/FinancingCompany/components/Filter.tsx
... ... @@ -26,7 +26,6 @@ export default function AccountList() {
26 26 }}
27 27 >
28 28 <Row style={{ display: "flex", flex: 1, alignItems: 'center' }}>
29   - <div>商家:</div>
30 29 <Col span={6}>
31 30 <Select
32 31 placeholder="请选择商家"
... ... @@ -44,7 +43,6 @@ export default function AccountList() {
44 43 ))}
45 44 </Select>
46 45 </Col>
47   - <div style={{ marginLeft: 20 }}>品牌:</div>
48 46 <Col span={6}>
49 47 <Select
50 48 placeholder="请选择品牌"
... ...
src/pages/finance/SpecialAccount/FinancingCompany/components/List.tsx
... ... @@ -39,7 +39,7 @@ export default function SalesFinanceList() {
39 39 }
40 40 >
41 41 <span>
42   - 保证金&nbsp;&nbsp;
  42 + 还款保证金账户&nbsp;&nbsp;
43 43 <ExclamationCircleFilled style={{ color: "#40a9ff" }} />
44 44 </span>
45 45 </Popover>
... ...
src/pages/mkt/ActivityCreate/ExternalPromotion/components/ActivityFlow/SignUp.tsx
... ... @@ -56,6 +56,8 @@ export default function index() {
56 56 // pa.awardConfigs.
57 57 }
58 58 changePa.joinLimitNum = pa.joinLimitNum;
  59 + changePa.signUpPrice = pa.signUpPrice;
  60 + changePa.saleOrderAmount = pa.saleOrderAmount;
59 61 changePa.awardConfigs = pa.awardConfigs;
60 62 changePa.activityNo = activityNo;
61 63 }
... ... @@ -141,7 +143,7 @@ export default function index() {
141 143 precision={2}
142 144 addonAfter="元"
143 145 style={{ width: "100%" }}
144   - disabled={readOnly}
  146 + disabled={readOnly && !changeEnable}
145 147 />
146 148 </Form.Item>
147 149 {bizType === 2 && (
... ... @@ -161,7 +163,7 @@ export default function index() {
161 163 precision={2}
162 164 addonAfter="元"
163 165 style={{ width: "100%" }}
164   - disabled={readOnly}
  166 + disabled={readOnly && !changeEnable}
165 167 />
166 168 </Form.Item>
167 169 )}
... ...
src/pages/oop/Car/components/CarList.tsx
... ... @@ -21,6 +21,11 @@ export default function CarList() {
21 21 align: "center",
22 22 },
23 23 {
  24 + title: '车型分类名称',
  25 + dataIndex: 'classifyName',
  26 + align: "center",
  27 + },
  28 + {
24 29 title: '配置名称',
25 30 dataIndex: 'name',
26 31 width: "13%",
... ...
src/pages/oop/Car/components/CarModal.tsx
... ... @@ -431,6 +431,7 @@ export default function CarModal() {
431 431 ))}
432 432 </Select>
433 433 </FormItem>
  434 +
434 435 <FormItem
435 436 style={{ width: 400 }}
436 437 name="specCode"
... ... @@ -501,6 +502,14 @@ export default function CarModal() {
501 502 <Input.TextArea autoSize allowClear />
502 503 </FormItem>
503 504 <FormItem
  505 + name="classifyName"
  506 + label="车型分类名称"
  507 + style={{ width: 400 }}
  508 + rules={[{ required: true, message: "该选项为必填项" }]}
  509 + >
  510 + <Input placeholder="请输入" allowClear />
  511 + </FormItem>
  512 + <FormItem
504 513 style={{ width: 400 }}
505 514 name="energyType"
506 515 label="能源类型"
... ...
src/pages/order3/AddValueTaskConfig/api.ts
... ... @@ -24,6 +24,8 @@ export interface ListResult {
24 24 endTime?: number // 结束时间
25 25 enable?: boolean // 启用/禁用
26 26 addedValueType?: number // 附加值类型
  27 + vciOutputValueTask?: number // 商业险产值目标
  28 + decoOutputValueTask?: number // 装潢产值目标
27 29 }
28 30  
29 31 /** 查询附加值任务配置服务列表 */
... ...
src/pages/order3/AddValueTaskConfig/components/EditModal.tsx
1 1 import React, { useState, useEffect } from 'react';
2   -import { Modal, Button, message, Form, InputNumber, DatePicker, Radio } from 'antd';
  2 +import { Modal, Button, message, Form, InputNumber, DatePicker, Radio, Row, Col } from 'antd';
3 3 import {useStore} from '../index';
4 4 import {ListResult, saveConfigApi} from '../api';
5 5 import { debounce, isNil } from 'lodash';
... ... @@ -57,7 +57,9 @@ export default function DetailModal() {
57 57 decoOutputValueRatio: currentData.data?.decoOutputValueRatio,
58 58 shopList: currentData.data?.shopList?.map((v: any) => ({value: v.shopId, label: v.shopName})) || [],
59 59 rangeDate: [moment(currentData.data.beginTime), moment(currentData.data.endTime)],
60   - addedValueType: currentData?.data.addedValueType
  60 + addedValueType: currentData?.data?.addedValueType,
  61 + vciOutputValueTask: currentData?.data?.vciOutputValueTask,
  62 + decoOutputValueTask: currentData?.data?.decoOutputValueTask
61 63 });
62 64 setType(currentData.data?.addedValueType || 2);
63 65 };
... ... @@ -75,7 +77,9 @@ export default function DetailModal() {
75 77 shopList: params.shopList.map((v: any) => ({shopId: v.value, shopName: v.label})),
76 78 beginTime: moment(params.rangeDate[0]).valueOf(),
77 79 endTime: moment(params.rangeDate[1]).valueOf(),
78   - addedValueType: params.addedValueType
  80 + addedValueType: params.addedValueType,
  81 + vciOutputValueTask: params.vciOutputValueTask,
  82 + decoOutputValueTask: params.decoOutputValueTask
79 83 };
80 84 saveConfigApi(_params)
81 85 .then(res => {
... ... @@ -129,6 +133,54 @@ export default function DetailModal() {
129 133 parser={(value: string) => value?.replace('元/台', '')}
130 134 />
131 135 </Form.Item>
  136 + <Row style={{marginLeft: 30}}>
  137 +
  138 + <Form.Item
  139 + label={<span>其中:<span>商业险产值目标</span></span>}
  140 + name="vciOutputValueTask"
  141 + style={{width: '100%'}}
  142 + rules={[({ getFieldValue }) => ({
  143 + validator(_, value) {
  144 + if (isNil(value)) {
  145 + return Promise.reject(new Error('请输入'));
  146 + }
  147 + return Promise.resolve();
  148 + },
  149 + })]}
  150 + >
  151 + <InputNumber
  152 + style={{width: '100%'}}
  153 + controls={false}
  154 + min={0}
  155 + formatter={(value: any) => `${value}元/台`}
  156 + precision={2}
  157 + parser={(value: string) => value?.replace('元/台', '')}
  158 + />
  159 + </Form.Item>
  160 + <Form.Item
  161 + label={<span style={{textIndent: '42px'}}>装潢产值目标</span>}
  162 + name="decoOutputValueTask"
  163 + style={{width: '100%'}}
  164 + rules={[({ getFieldValue }) => ({
  165 + validator(_, value) {
  166 + if (isNil(value)) {
  167 + return Promise.reject(new Error('请输入'));
  168 + }
  169 + return Promise.resolve();
  170 + },
  171 + })]}
  172 + >
  173 + <InputNumber
  174 + style={{width: '100%'}}
  175 + controls={false}
  176 + min={0}
  177 + formatter={(value: any) => `${value}元/台`}
  178 + precision={2}
  179 + parser={(value: string) => value?.replace('元/台', '')}
  180 + />
  181 + </Form.Item>
  182 + </Row>
  183 +
132 184 <div className="addValue_wrapper"><span className="addvalue_text">&#65290;</span><span>产值构成:</span></div>
133 185 <Form.Item
134 186 label={type === 2 ? "1.计算保险毛利" : "1.计算保险产值:"}
... ...
src/pages/order3/AddValueTaskConfig/components/List.tsx
... ... @@ -43,13 +43,19 @@ export default function LargeList({addedValueType} : Props) {
43 43 rowKey="id"
44 44 pagination={paginationConfig}
45 45 >
46   - <Column
  46 + <Column
47 47 title="单车附加值目标"
48 48 dataIndex="addedValueTask"
49 49 align="left"
50 50 render={(_text) => (isNil(_text) ? '-' : <span style={{color: "#FF921C", fontSize: '14px'}}>{_text}元<span style={{color: "#333"}}>/台</span></span>)}
51 51 />
52 52 <Column
  53 + title="商业险产值目标"
  54 + dataIndex="vciOutputValueTask"
  55 + align="left"
  56 + render={(_text) => (isNil(_text) ? '-' : <div style={{display: 'flex', flexDirection: 'column'}}><span style={{color: "#FF921C", fontSize: '14px'}}>{_text}元<span style={{color: "#333"}}>/台</span></span><span>(含驾意险)</span></div>)}
  57 + />
  58 + <Column
53 59 title={addedValueType === 2 ? "计算保险毛利" : "计算保险产值"}
54 60 dataIndex="addedValueTask"
55 61 align="left"
... ... @@ -61,6 +67,12 @@ export default function LargeList({addedValueType} : Props) {
61 67 </div>
62 68 )}
63 69 />
  70 + <Column
  71 + title="装潢产值目标"
  72 + dataIndex="decoOutputValueTask"
  73 + align="left"
  74 + render={(_text) => (isNil(_text) ? '-' : <span style={{color: "#FF921C", fontSize: '14px'}}>{_text}元<span style={{color: "#333"}}>/台</span></span>)}
  75 + />
64 76 <Column
65 77 title={addedValueType === 2 ? "计算装潢毛利" : "计算装潢产值"}
66 78 dataIndex="decoOutputValueRatio"
... ...
src/pages/performance/EvaDataImport/api.ts
... ... @@ -52,3 +52,17 @@ export function evaDataIndApi(): http.PromiseResp&lt;any&gt; {
52 52 export function saveEvaImportData(params: { key: string }) {
53 53 return request.get(`${MORAX_HOST}/erp/eval-indicator/save-import`, { params });
54 54 }
  55 +
  56 +/** 下载人员模板
  57 + * http://testgate.feewee.cn/morax/erp/eval-indicator/import-detail
  58 + */
  59 +export function upLoadStaffApi(): http.PromiseResp<any> {
  60 + return request.get(`${MORAX_HOST}/erp/eval-indicator/staff/template-file`, {});
  61 +}
  62 +
  63 +/** 下载门店模板
  64 + * http://testgate.feewee.cn/morax/erp/eval-indicator/import-detail
  65 + */
  66 +export function upLoadShopApi(): http.PromiseResp<any> {
  67 + return request.get(`${MORAX_HOST}/erp/eval-indicator/shop/template-file`, {});
  68 +}
... ...
src/pages/performance/EvaDataImport/index.tsx
... ... @@ -2,7 +2,8 @@ import React, { useState } from &quot;react&quot;;
2 2 import { PageHeaderWrapper } from "@ant-design/pro-layout";
3 3 import { Button, Card, Table, Row, message, Space, Typography, Divider, Switch, Upload } from "antd";
4 4 import usePagination from "@/hooks/usePagination";
5   -import { evaDataListApi } from "./api";
  5 +import useInitial from "@/hooks/useInitail";
  6 +import { evaDataListApi, upLoadStaffApi, upLoadShopApi } from "./api";
6 7 import { UploadOutlined } from "@ant-design/icons";
7 8 import type { UploadProps } from "antd";
8 9 import { history } from "umi";
... ... @@ -16,8 +17,12 @@ export default () =&gt; {
16 17 const { loading, list, paginationConfig, setParams, innerParams } = usePagination(evaDataListApi, {
17 18 pageSize: 10,
18 19 });
  20 + const { data: upLoadStaff, loading: upLoadStaffLoading } = useInitial(upLoadStaffApi, [], {});
  21 + const { data: upLoadShop, loading: upLoadShopLoading } = useInitial(upLoadShopApi, [], {});
19 22 const [fileData, setFileData] = useState({});
20 23 const [visible, setVisible] = useState<boolean>(false);
  24 + console.log("upLoadStaff", upLoadStaff);
  25 + console.log("upLoadShop", upLoadShop);
21 26 const uploadPerson: UploadProps = {
22 27 name: "file",
23 28 action: "/api/morax/erp/eval-indicator/analysis-staff",
... ... @@ -59,21 +64,13 @@ export default () =&gt; {
59 64 <Row style={{ marginBottom: 10 }} justify="space-between">
60 65 <Filter setParams={setParams} />
61 66 <div>
62   - <Button type="default" style={{ marginRight: 10 }}>
63   - <a
64   - href="https://gate.feewee.cn/file/download?fid=74d1d724f9be48baa5921f3782037c3b"
65   - target="_blank"
66   - rel="noreferrer"
67   - >
  67 + <Button type="default" style={{ marginRight: 10 }} loading={upLoadStaffLoading}>
  68 + <a href={upLoadStaff} target="_blank" rel="noreferrer">
68 69 下载人员模板
69 70 </a>
70 71 </Button>
71   - <Button type="default" style={{ marginRight: 10 }}>
72   - <a
73   - href="https://gate.feewee.cn/file/download?fid=e4eb136962164264a78753bd1d6061f3"
74   - target="_blank"
75   - rel="noreferrer"
76   - >
  72 + <Button type="default" style={{ marginRight: 10 }} loading={upLoadShopLoading}>
  73 + <a href={upLoadShop} target="_blank" rel="noreferrer">
77 74 下载门店模板
78 75 </a>
79 76 </Button>
... ... @@ -87,12 +84,7 @@ export default () =&gt; {
87 84 </Upload>
88 85 </div>
89 86 </Row>
90   - <Table
91   - loading={loading}
92   - rowKey={(row) => `id${row.id}`}
93   - dataSource={list}
94   - pagination={paginationConfig}
95   - >
  87 + <Table loading={loading} rowKey={(row) => `id${row.id}`} dataSource={list} pagination={paginationConfig}>
96 88 <Column
97 89 title="导入时间"
98 90 dataIndex="createTime"
... ...
src/pages/performance/EvaGroupSetting/EditComfirm/components/AddRewardsModal.tsx
... ... @@ -219,7 +219,6 @@ export default function CreateModal(props: Props) {
219 219 onChange={(value) => {
220 220 const _type = value;
221 221 setCalType(_type);
222   - console.log(calType);
223 222 }}
224 223 >
225 224 <Option value={1} key={1}>
... ... @@ -343,27 +342,29 @@ export default function CreateModal(props: Props) {
343 342 >
344 343 {({ getFieldValue }) => {
345 344 const rankType = getFieldValue("rankType");
346   - if (rankType == 1 && !currentItem.ladders) {
  345 + if (rankType == 1 && (!currentItem.ladders || currentItem.ladders.length == 0)) {
347 346 form.setFieldValue("ladders", [{ lower: 1, money: 0, key: 0, rankOrderType: 1 }]);
348   - } else if (rankType == 2 && !currentItem.ladders) {
  347 + } else if (rankType == 2 && (!currentItem.ladders || currentItem.ladders.length == 0)) {
  348 + form.setFieldValue("ladders", [{ lower: 0, money: 0, key: 0, rankOrderType: 1 }]);
  349 + } else if (!rankType && (!currentItem.ladders || currentItem.ladders.length == 0)) {
349 350 form.setFieldValue("ladders", [{ lower: 0, money: 0, key: 0, rankOrderType: 1 }]);
350 351 }
351   - return (
352   - <Form.Item
353   - name="ladders"
354   - label="排名设置"
355   - rules={[{ required: true, message: "请配置排名" }]}
356   - style={{ width: "100%" }}
357   - >
358   - <RankModal
359   - visible
360   - isPercent={isPercent}
361   - laddersType={currentItem?.laddersType}
362   - calType={calType}
363   - rankType={rankType}
364   - />
365   - </Form.Item>
366   - );
  352 + return (
  353 + <Form.Item
  354 + name="ladders"
  355 + label="排名设置"
  356 + rules={[{ required: true, message: "请配置排名" }]}
  357 + style={{ width: "100%" }}
  358 + >
  359 + <RankModal
  360 + visible
  361 + isPercent={isPercent}
  362 + laddersType={currentItem?.laddersType}
  363 + calType={calType}
  364 + rankType={rankType}
  365 + />
  366 + </Form.Item>
  367 + );
367 368 }}
368 369 </Form.Item>
369 370 </>
... ... @@ -433,11 +434,12 @@ export default function CreateModal(props: Props) {
433 434 >
434 435 {({ getFieldValue }) => {
435 436 const caculateType = getFieldValue("calMethod");
  437 + // console.log(caculateType, currentItem);
436 438 //阶梯(总)
437 439 if (caculateType == 3 || caculateType == 5) {
438   - if (caculateType == 3 && !currentItem.ladders) {
  440 + if (caculateType == 3 && (!currentItem.ladders || currentItem.ladders.length == 0)) {
439 441 form.setFieldValue("ladders", [{ lower: 0, money: 0, key: 0 }]);
440   - } else if (caculateType == 5 && !currentItem.ladders) {
  442 + } else if (caculateType == 5 && (!currentItem.ladders || currentItem.ladders.length == 0)) {
441 443 form.setFieldValue("ladders", [{ lower: 0, money: 0, capMoney: 0, key: 0 }]);
442 444 }
443 445 return (
... ...
src/pages/performance/EvaGroupSetting/EditComfirm/components/CondLaddersTable.tsx
... ... @@ -205,10 +205,11 @@ const LadderTable = ({ value, onChange, readOnly, visible, type, setladderVisibl
205 205 render: (value: number) => (value && value !== 65536 ? value + "%" : ""),
206 206 },
207 207 {
208   - title: "标准分",
  208 + title: "绩效分折算比例",
209 209 dataIndex: "scorePercent",
210 210 width: "15%",
211 211 editable: true,
  212 + render: (value: number) => value + "%",
212 213 },
213 214 {
214 215 title: "操作",
... ...
src/pages/performance/EvaGroupSetting/EditComfirm/components/RankModal.tsx
... ... @@ -166,6 +166,7 @@ const TotalAmount = ({
166 166 };
167 167  
168 168 const _add = async (key: React.Key, record: Item) => {
  169 + // console.log("record.key", record.key);
169 170 try {
170 171 const row = (await form.validateFields()) as Item;
171 172 let newData = [...value.map((i) => ({ ...i }))];
... ... @@ -320,7 +321,11 @@ const TotalAmount = ({
320 321 const editable = isEditing(record);
321 322 return editable ? (
322 323 <Space split={<Divider type="vertical" />}>
323   - <Typography.Link onClick={() => _add(record.key, record)} style={{ marginRight: 8 }}>
  324 + <Typography.Link
  325 + onClick={() => _add(record.key, record)}
  326 + style={{ marginRight: 8 }}
  327 + disabled={index !== value?.length - 1}
  328 + >
324 329 保存并新增排名区间
325 330 </Typography.Link>
326 331 <Typography.Link onClick={() => save(record.key, record)} style={{ marginRight: 8 }}>
... ...
src/pages/performance/KpiGroupSetting/EditComfirm/components/CondLaddersTable.tsx
... ... @@ -202,13 +202,14 @@ const LadderTable = ({ value, onChange, readOnly, visible, type, setladderVisibl
202 202 dataIndex: "upper",
203 203 width: "20%",
204 204 editable: true,
205   - render: (value: number) => ((value && value !== 65536) ? (value + "%") : ""),
  205 + render: (value: number) => (value && value !== 65536 ? value + "%" : ""),
206 206 },
207 207 {
208   - title: "标准分",
  208 + title: "绩效分折算比例",
209 209 dataIndex: "scorePercent",
210 210 width: "15%",
211 211 editable: true,
  212 + render: (value: number) => value + "%",
212 213 },
213 214 {
214 215 title: "操作",
... ...
src/pages/pms/comonents/PmsSelect.tsx
... ... @@ -7,8 +7,7 @@ export default function Index(props: SelectProps) {
7 7 <Select
8 8 {...props}
9 9 showSearch
10   - // optionFilterProp="children"
11   - filterOption={(input: any, option: any) => option.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
  10 + optionFilterProp="label"
12 11 />
13 12 );
14 13 }
15 14 \ No newline at end of file
... ...
src/pages/pms/partPlan/CustBuyPlan/subpages/First/components/PartModal.tsx
... ... @@ -73,7 +73,7 @@ export default function DetailModal() {
73 73 align="center"
74 74 render={r => (
75 75 <>
76   - <Popconfirm
  76 + {/* <Popconfirm
77 77 title="确定删除?"
78 78 onConfirm={() => deletePart(r)}
79 79 okText="确定"
... ... @@ -81,7 +81,7 @@ export default function DetailModal() {
81 81 >
82 82 <a>删除</a>
83 83 </Popconfirm>
84   - <Divider type="vertical" />
  84 + <Divider type="vertical" /> */}
85 85 <a onClick={() => onFinish(r)}>完成</a>
86 86 </>
87 87 )}
... ...
src/pages/pms/partPlan/PlanManage/api.ts
... ... @@ -20,13 +20,13 @@ export interface Params {
20 20 * 列表项
21 21 */
22 22 export interface ListVO {
23   - planId?: string; // 计划Id
  23 + planId?: number; // 计划Id
24 24 planNo?: string; // 计划单号
25 25 brandId?: string; // 品牌ID
26 26 planDate?: string; // 计划日期
27 27 approvalOrderNo?: string; // 审核单号
28 28 userName?: string; // 计划人员
29   - status?: string; // 计划状态 1:待审核2:已通过9:已拒绝
  29 + status?: number; // 计划状态 1:待审核2:已通过9:已拒绝
30 30 settleShopId?: string; // 结算门店门店id
31 31 settleShopName?: string; // 结算门店名称
32 32 prepayToken?: string; // 预付token
... ...
src/pages/pms/partPlan/PlanManage/components/DetailModal.tsx
... ... @@ -6,7 +6,7 @@ import ProgressView from &quot;./ProgressView&quot;;
6 6 import ShippingDetailModal from './ShippingDetailModal';
7 7 import PartDetailModal from './PartDetailModal';
8 8 import {flattenDeep} from "@/pages/pms/entity";
9   -import {getDetail, DetailVO} from "@/pages/pms/partPlan/PlanManage/subpages/Detail/api";
  9 +import {getDetail, DetailVO, Item} from "@/pages/pms/partPlan/PlanManage/subpages/Detail/api";
10 10  
11 11 interface Props {
12 12 visible: boolean,
... ... @@ -22,12 +22,12 @@ export default function DetailModal(props: Props) {
22 22 // @ts-ignore
23 23 const { data: progresss, setParams: setProgresssParams } = useInitial<ProgressVO[], Params>(getProgressDetail, [], params, delay);
24 24 // @ts-ignore
25   - const { data, setParams, loading } = useInitial<DetailVO[], Params>(getDetail, [], params, delay);
  25 + const { data, setParams, loading } = useInitial<Item, Params>(getDetail, {}, params, delay);
26 26 const [visibleDetail, setVisibleDetail] = useState(false);
27 27 const [_item, setItem] = useState<SubmitListVO>({});
28 28 const [visiblePartDetail, setVisiblePartDetail] = useState(false);
29 29 const suppliers = useMemo(() => {
30   - return flattenDeep(data.map((it: DetailVO) => (it.suppliers || []).map(su => ({...it, ...su}))));
  30 + return flattenDeep(data.list?.map((it: DetailVO) => (it.suppliers || []).map(su => ({...it, ...su}))));
31 31 }, [data]);
32 32  
33 33 useEffect(() => {
... ...
src/pages/pms/partPlan/PlanManage/index.tsx
... ... @@ -13,6 +13,7 @@ import DetailModal from &quot;@/pages/pms/partPlan/PlanManage/components/DetailModal&quot;
13 13  
14 14 // 计划状态 1:待审核2:已通过3待付款4已付款9:已拒绝
15 15 const statusName: {[key: number]: string} = {
  16 + 0: '草稿',
16 17 1: '待审核',
17 18 2: '已通过',
18 19 3: '待付款',
... ... @@ -69,6 +70,7 @@ export default function Index() {
69 70 onChange={v => setParams({status: v }, true)}
70 71 optionFilterProp="children"
71 72 >
  73 + <Select.Option value={0} key={0}>草稿</Select.Option>
72 74 <Select.Option value={1} key={1}>待审核</Select.Option>
73 75 <Select.Option value={2} key={2}>已通过</Select.Option>
74 76 <Select.Option value={9} key={9}>已拒绝</Select.Option>
... ... @@ -95,9 +97,16 @@ export default function Index() {
95 97 fixed="right"
96 98 render={(text, _item: ListVO) => (
97 99 <>
98   - <a onClick={() => history.push(`/pms/partPlan/planManage/detail/${_item.planId}`)}>
99   - 查看
100   - </a>
  100 + {[0, 9].includes(_item.status || 0) ? (
  101 + <a onClick={() => history.push(`/pms/partPlan/planManage/apply?planId=${_item.planId}`)}>
  102 + 编辑
  103 + </a>
  104 + )
  105 + : (
  106 + <a onClick={() => history.push(`/pms/partPlan/planManage/detail/${_item.planId}`)}>
  107 + 查看
  108 + </a>
  109 + )}
101 110 <Divider type="vertical" />
102 111 <a onClick={() => {
103 112 setItem(_item);
... ...
src/pages/pms/partPlan/PlanManage/subpages/Apply/api.ts
... ... @@ -16,3 +16,9 @@ export interface SaveParams {
16 16 export function saveApi(params?: SaveParams): http.PromiseResp<void> {
17 17 return request.post(`${PMS_HOST}/erp/plan/pool/save/plan`, params);
18 18 }
  19 +/**
  20 + * 草稿
  21 + */
  22 +export function draftApi(params?: SaveParams): http.PromiseResp<void> {
  23 + return request.post(`${PMS_HOST}/erp/plan/pool/save/draft`, params);
  24 +}
... ...
src/pages/pms/partPlan/PlanManage/subpages/Apply/components/DealerModal.tsx
... ... @@ -11,9 +11,9 @@ interface Props {
11 11 }
12 12 const {Option} = Select;
13 13 export default function Index({ onCancel, visible, onOk, dealerList = [] }: Props) {
14   - const [dealer, setDealer] = useState<any>({dealerId: null, dealerName: null});
  14 + const [dealer, setDealer] = useState<any>({ settleDealerId: null, settleDealerName: null});
15 15 const { data: dealers } = useInitail<CommonApi.OptionVO[], CommonApi.DealerParam>(getDealerApi, [], {});
16   - const suIds = dealerList.map(it => it.dealerId);
  16 + const suIds = dealerList.map(it => it.settleDealerId);
17 17  
18 18 useEffect(() => {
19 19 if (!visible) {
... ... @@ -22,7 +22,7 @@ export default function Index({ onCancel, visible, onOk, dealerList = [] }: Prop
22 22 }, [visible]);
23 23  
24 24 const handSave = () => {
25   - if (!dealer.dealerId) {
  25 + if (!dealer.settleDealerId) {
26 26 message.error('请选择采购商家');
27 27 return;
28 28 }
... ... @@ -40,7 +40,7 @@ export default function Index({ onCancel, visible, onOk, dealerList = [] }: Prop
40 40 <Button key="cancel" onClick={onCancel}>取消</Button>,
41 41 <Button
42 42 key="submit"
43   - disabled={!dealer.dealerId}
  43 + disabled={!dealer.settleDealerId}
44 44 onClick={handSave}
45 45 type="primary"
46 46 htmlType="submit"
... ... @@ -52,14 +52,14 @@ export default function Index({ onCancel, visible, onOk, dealerList = [] }: Prop
52 52 <div style={{display: 'flex', flexDirection: 'row', alignItems: 'center', marginBottom: 10}}>
53 53 <span>商家:</span>
54 54 <Select
55   - value={dealer.dealerId}
  55 + value={dealer.settleDealerId}
56 56 style={{ width: 250 }}
57 57 placeholder="请选择商家"
58 58 showSearch
59 59 optionFilterProp="children"
60   - onChange={(dealerId) => {
61   - const d = dealers.find(it => it.id == dealerId) || {};
62   - setDealer({dealerId, dealerName: d.name});
  60 + onChange={(settleDealerId) => {
  61 + const d = dealers.find(it => it.id == settleDealerId) || {};
  62 + setDealer({ settleDealerId, settleDealerName: d.name});
63 63 }}
64 64 >
65 65 {dealers.filter(it => !suIds.includes(it.id)).map((b) => (
... ...
src/pages/pms/partPlan/PlanManage/subpages/Apply/index.tsx
1   -import {Card, ConfigProvider, Select, Button, message, Popconfirm} from 'antd';
  1 +import {Card, ConfigProvider, Select, Button, message, Popconfirm, Input} from 'antd';
2 2 import { PageHeaderWrapper } from '@ant-design/pro-layout';
3 3 import React, {useEffect, useState} from "react";
4 4 import DealerModal from './components/DealerModal';
... ... @@ -8,16 +8,25 @@ import {throttle, sum} from &#39;lodash&#39;;
8 8 import useInitial from "@/hooks/useInitail";
9 9 import * as API from "@/common/api";
10 10 import {getList, Params, ListVO} from "@/pages/pms/partPlan/PlanPool/api";
11   -import {saveApi} from './api';
  11 +import {saveApi, draftApi} from './api';
12 12 import zhCN from "antd/lib/locale-provider/zh_CN";
13 13 import st from "@/pages/pms/partPlan/PlanManage/style.less";
14   -import StepBnt from "@/pages/pms/comonents/StepBnt";
15 14 import PartModal from "@/pages/pms/partPlan/PlanManage/subpages/Apply/components/PartModal";
16 15 import {groupBys, flattenDeep} from '@/pages/pms/entity';
17 16 import {PartDetail} from '../../api';
  17 +import { history } from 'umi';
  18 +import { getDetail, Params as detailParams, Item } from '../Detail/api';
  19 +import ImageUpload from '@/pages/decoration/deco/DeoGoodsManagement/components/ImageUpload';
18 20  
19 21 const { Option } = Select;
  22 +const apiObj: { [key: number]: any } = {
  23 + 1: saveApi,
  24 + 2: draftApi
  25 +};
20 26 export default function Index() {
  27 + const planId = history.location.query;
  28 + const [detaildelay, setDetaildelay] = useState(true);
  29 + const { data, setParams: detailsetParams } = useInitial<Item, detailParams>(getDetail, {}, { ...planId }, detaildelay);
21 30 const [delay, setDelay] = useState<boolean>(true);
22 31 const [loading, setLoading] = useState<boolean>(false);
23 32 const { data: brands } = useInitial(API.getBrandFilterApi, [], {});
... ... @@ -31,10 +40,30 @@ export default function Index() {
31 40 const [visiblePartDetail, setVisiblePartDetail] = useState(false);
32 41 const partList = flattenDeep(dealerList.map(it => (it.suppliers || []).map((su: any) => (su.storages || []).map((st: any) => (st.parts || [])))));
33 42 const poolIds = partList.map((it: any) => it.poolId);
  43 + const [imageVisible, setImageVisible] = useState(true);
  44 + const [info, setInfo] = useState<{ remark?: string, fids?: any }>();
  45 +
  46 + useEffect(() => {
  47 + if (planId?.planId) {
  48 + setDetaildelay(false);
  49 + detailsetParams({ ...planId }, true);
  50 + }
  51 + }, []);
  52 +
  53 + useEffect(() => {
  54 + if (data.list?.length) {
  55 + setImageVisible(false);
  56 + setDfParams({brandId: data.list[0].brandId});
  57 + setParams({}, true);
  58 + setDelay(false);
  59 + setDealerList(data.list);
  60 + setInfo({ remark: data.remark, fids: data.fids?.split(',').map(i => `/api/file/show?fid=${i}`) });
  61 + }
  62 + }, [data.list?.length]);
34 63  
35 64 function onOk(parts: ListVO[] = []) {
36 65 setDealerList(dealerList.map(it => {
37   - if (it.dealerId == dealer.dealerId) {
  66 + if (it.settleDealerId == dealer.settleDealerId) {
38 67 return {
39 68 ...it,
40 69 suppliers: (it.suppliers || []).map((su: any) => {
... ... @@ -64,7 +93,7 @@ export default function Index() {
64 93  
65 94 function onOkSupplier(supplier: any = {}) {
66 95 setDealerList(dealerList.map(it => {
67   - if (it.dealerId == dealer.dealerId) {
  96 + if (it.settleDealerId == dealer.settleDealerId) {
68 97 return {
69 98 ...it,
70 99 suppliers: [...(it.suppliers || []), supplier]
... ... @@ -76,7 +105,7 @@ export default function Index() {
76 105  
77 106 function deleteSupplier(dealer: any = {}, supplier: any = {}) {
78 107 setDealerList(dealerList.map(it => {
79   - if (it.dealerId == dealer.dealerId) {
  108 + if (it.settleDealerId == dealer.settleDealerId) {
80 109 return {
81 110 ...it,
82 111 suppliers: (it.suppliers || []).filter((su: any) => su.supplierId != supplier.supplierId)
... ... @@ -88,7 +117,7 @@ export default function Index() {
88 117  
89 118 function deletePart(dealer: any = {}, supplier: any = {}, storage: any = {}, part: any = {}) {
90 119 setDealerList(dealerList.map(it => {
91   - if (it.dealerId == dealer.dealerId) {
  120 + if (it.settleDealerId == dealer.settleDealerId) {
92 121 return {
93 122 ...it,
94 123 suppliers: (it.suppliers || []).map((su: any) => {
... ... @@ -116,7 +145,7 @@ export default function Index() {
116 145  
117 146 function deleteStorage(dealer: any = {}, supplier: any = {}, storage: any = {}) {
118 147 setDealerList(dealerList.map(it => {
119   - if (it.dealerId == dealer.dealerId) {
  148 + if (it.settleDealerId == dealer.settleDealerId) {
120 149 return {
121 150 ...it,
122 151 suppliers: (it.suppliers || []).map((su: any) => {
... ... @@ -134,31 +163,34 @@ export default function Index() {
134 163 }));
135 164 }
136 165  
137   - // useEffect(() => {
138   - // if (dfParams.brandId) {
139   - // setParams(dfParams, true);
140   - // setDelay(false);
141   - // }
142   - // }, [dfParams.brandId]);
143   -
144   - const onSubmit = throttle(() => {
  166 + const onSubmit = throttle((isSave) => {
145 167 setLoading(true);
146 168 let suppliers = flattenDeep(dealerList.map(de => (de.suppliers || []).map((su: any) => ({...de, ...su}))));
147 169 suppliers = suppliers.map(su => ({
148 170 ...su,
149   - settleDealerId: su.dealerId,
  171 + settleDealerId: su.settleDealerId,
150 172 storages: (su.storages || []).map((st: any) => ({
151 173 storageId: st.storageId,
152 174 poolIds: (st.parts || []).map((pa: any) => pa.poolId)
153 175 }))
154 176 }));
155   - saveApi({
  177 + const type = isSave ? 1 : 2;
  178 + apiObj[type]({
  179 + planId: Number(planId?.planId),
156 180 ...dfParams,
157   - suppliers
  181 + suppliers,
  182 + remark: info?.remark,
  183 + fids: info?.fids.map((i: any) => {
  184 + if (typeof i == 'object') {
  185 + return i.url.split('=')[1];
  186 + } else {
  187 + return i;
  188 + }
  189 + }).join()
158 190 }).then(() => {
159 191 setLoading(false);
160   - history.back();
161   - }).catch(e => {
  192 + history.goBack();
  193 + }).catch((e: any) => {
162 194 setLoading(false);
163 195 message.error(e.message);
164 196 });
... ... @@ -204,15 +236,15 @@ export default function Index() {
204 236 </a>
205 237 </div>
206 238 {dealerList.map((dealer: any = {}) => (
207   - <div key={`dealer${dealer.dealerId}`} style={{ marginTop: 10 }}>
  239 + <div key={`dealer${dealer.settleDealerId}`} style={{ marginTop: 10 }}>
208 240 <div style={{ display: 'flex', flexDirection: 'row', alignItems: 'center'}}>
209   - <div style={{ fontWeight: "bold" }}>{`商家: ${dealer.dealerName || ''}`}</div>
  241 + <div style={{ fontWeight: "bold" }}>{`商家: ${dealer.settleDealerName || ''}`}</div>
210 242 <a style={{marginLeft: 40}} onClick={() => { setVisibleSupplier(true); setDealer(dealer); }}>
211 243 添加指定供应商
212 244 </a>
213 245 <Popconfirm
214 246 title="是否删除"
215   - onConfirm={() => setDealerList(dealerList.filter(it => it.dealerId!=dealer.dealerId))}
  247 + onConfirm={() => setDealerList(dealerList.filter(it => it.settleDealerId!=dealer.settleDealerId))}
216 248 okText="确定"
217 249 cancelText="取消"
218 250 style={{marginLeft: 20}}
... ... @@ -224,8 +256,6 @@ export default function Index() {
224 256 </div>
225 257 {(dealer.suppliers || []).map((supplier: any = {}) => {
226 258 const paList: any[] = flattenDeep((supplier.storages || []).map((st: any) => (st.parts || [])));
227   - // const paList: any[] = pas.length > 0 ? pas[0] : [];
228   - console.log('pas', paList);
229 259 return (
230 260 <div key={`supplier${supplier.supplierId}`} style={{ marginTop: 10, marginLeft: 40 }}>
231 261 <div style={{ display: 'flex', flexDirection: 'row', alignItems: 'center'}}>
... ... @@ -247,7 +277,7 @@ export default function Index() {
247 277 </div>
248 278 <div style={{display: 'flex', marginLeft: 40, marginTop: 10}}>
249 279 <div style={{marginRight: 20}}>
250   - {`总金额: ${sum(paList.map((it: any) => (it.price || 0) * (it.count || 0))).toFixed(2)}元`}
  280 + {`总金额: ${sum(paList.map((it: any) => (it.price || 0) * (it.count || it.partCnt || 0))).toFixed(2)}元`}
251 281 </div>
252 282 <div>{`品种数: ${[...new Set((paList || []).map((i: PartDetail) => i.partCode))].length}种`}</div>
253 283 </div>
... ... @@ -255,7 +285,7 @@ export default function Index() {
255 285 <div key={`storage${storage.storageId}`} style={{ marginTop: 10, marginLeft: 60 }}>
256 286 <div style={{ display: 'flex', flexDirection: 'row', alignItems: 'center'}}>
257 287 <div style={{ fontWeight: "bold" }}>{`发运库房: ${storage.storageName || ''}`}</div>
258   - <div style={{marginLeft: 20}}>{`总金额: ${sum((storage.parts || []).map((it: any) => (it.price || 0) * (it.count || 0))).toFixed(2)}元`}</div>
  288 + <div style={{marginLeft: 20}}>{`总金额: ${sum((storage.parts || []).map((it: any) => (it.price || 0) * (it.count || it.partCnt || 0))).toFixed(2)}元`}</div>
259 289 <div style={{marginLeft: 20}}>{`品种数: ${[...new Set((storage.parts || []).map((i: PartDetail) => i.partCode))].length}种`}</div>
260 290 <a style={{marginLeft: 20}} onClick={() => { setVisiblePartDetail(true); setDealer({dealer, supplier, storage }); }}>
261 291 查看配件
... ... @@ -308,11 +338,49 @@ export default function Index() {
308 338 deletePart={deletePart}
309 339 />
310 340 </div>
311   - <StepBnt
312   - disable={loading}
313   - bntLoading={loading}
314   - submit={onSubmit}
315   - />
  341 + <div style={{display: 'flex', alignItems: 'flex-start', marginBottom: 20}}>
  342 + <span style={{marginRight: 10}}>备注:</span>
  343 + <Input.TextArea rows={2} style={{ width: 250 }} value={info?.remark} onChange={e => setInfo({...info, remark: e.target.value})} />
  344 + </div>
  345 + <div style={{ display: 'flex', alignItems: 'flex-start' }}>
  346 + <span style={{ marginRight: 10 }}>附件:</span>
  347 + <ImageUpload
  348 + length={6}
  349 + clear={imageVisible}
  350 + value={info?.fids}
  351 + onChange={v => {
  352 + const ids = v.fileList.map(it => it?.response?.data || it);
  353 + setInfo({ ...info, fids: ids });
  354 + }}
  355 + />
  356 + </div>
  357 + <div style={{display: 'flex', justifyContent: 'center'}}>
  358 + <Button
  359 + disabled={loading}
  360 + loading={loading}
  361 + style={{marginRight: 20}}
  362 + onClick={() => { setImageVisible(true); history.goBack(); }}
  363 + >
  364 + 取消
  365 + </Button>
  366 + <Button
  367 + disabled={loading}
  368 + loading={loading}
  369 + onClick={() => onSubmit(false)}
  370 + type="primary"
  371 + style={{marginRight: 20}}
  372 + >
  373 + 暂存为草稿
  374 + </Button>
  375 + <Button
  376 + disabled={loading}
  377 + loading={loading}
  378 + onClick={() => onSubmit(true)}
  379 + type="primary"
  380 + >
  381 + 确认并提交
  382 + </Button>
  383 + </div>
316 384 </Card>
317 385 </ConfigProvider>
318 386 </PageHeaderWrapper>
... ...
src/pages/pms/partPlan/PlanManage/subpages/Detail/api.ts
... ... @@ -7,6 +7,7 @@ import { PMS_HOST } from &#39;@/utils/host&#39;;
7 7 */
8 8 export interface DetailVO {
9 9 brandName?: string; // 品牌名称
  10 + brandId?: number; // 品牌ID
10 11 settleDealerName?: string; // 结算商家
11 12 settleShopName?: string; // 结算门店
12 13 suppliers?: SupplierVO[]; // 配件集合
... ... @@ -47,9 +48,55 @@ export interface Params {
47 48 planNo?: string;
48 49 no?: string;
49 50 }
  51 +export interface Item {
  52 + /**
  53 + * 计划单号
  54 + */
  55 + planNo?: string;
  56 + /**
  57 + * 品牌ID
  58 + */
  59 + brandId?: number;
  60 + /**
  61 + * 计划日期
  62 + */
  63 + planDate?: string;
  64 + /**
  65 + * 审核单号
  66 + */
  67 + approvalOrderNo?: string;
  68 + /**
  69 + * 计划人员
  70 + */
  71 + userName?: string;
  72 + /**
  73 + * 库销比
  74 + */
  75 + ratio?: number;
  76 + /**
  77 + * 计划库销比
  78 + */
  79 + planRatio?: number;
  80 + /**
  81 + * 计划状态 1:待审核2:已通过9:已拒绝
  82 + */
  83 + status?: string;
  84 + /**
  85 + * 备注
  86 + */
  87 + remark?: string;
  88 + /**
  89 + * 附件
  90 + */
  91 + fids?: string;
  92 + /**
  93 + * 计划列表
  94 + */
  95 + list?: DetailVO[];
  96 +}
50 97 /**
51 98 * 查询明细
52 99 */
53   -export function getDetail(params?: Params): http.PromiseResp<DetailVO[]> {
  100 +export function getDetail(params?: Params): http.PromiseResp<Item> {
54 101 return request.get(`${PMS_HOST}/erp/part/plan/get/plan/group/detail`, { params });
55 102 }
... ...
src/pages/pms/partPlan/PlanManage/subpages/Detail/index.tsx
1   -import {Card, ConfigProvider, Spin} from 'antd';
  1 +import { Card, ConfigProvider, Spin, Upload } from 'antd';
2 2 import { PageHeaderWrapper } from '@ant-design/pro-layout';
3 3 import React, {useState} from "react";
4 4 import useInitial from "@/hooks/useInitail";
5   -import {getDetail, DetailVO, Params, SupplierVO, StorageVO, PartVO} from "./api";
  5 +import { getDetail, Item, Params, SupplierVO, StorageVO, PartVO, DetailVO } from "./api";
6 6 import zhCN from "antd/lib/locale-provider/zh_CN";
7 7 import st from "@/pages/pms/partPlan/PlanManage/style.less";
8 8 import StepBnt from "@/pages/pms/comonents/StepBnt";
... ... @@ -14,7 +14,7 @@ import PartDetailModal from &#39;./components/PartDetailModal&#39;;
14 14  
15 15 export default function Index({ match }: common.ConnectProps) {
16 16 const { planId } = match.params;
17   - const { data, loading } = useInitial<DetailVO[], Params>(getDetail, [], {planId});
  17 + const { data, loading } = useInitial<Item, Params>(getDetail, {}, {planId});
18 18 const [visiblePart, setVisiblePart] = useState(false);
19 19 const [parts, setParts] = useState<PartVO[]>([]);
20 20  
... ... @@ -23,7 +23,7 @@ export default function Index({ match }: common.ConnectProps) {
23 23 <Spin spinning={loading}>
24 24 <ConfigProvider locale={zhCN}>
25 25 <Card className={st.page}>
26   - {data.map((dealer: DetailVO = {}) => (
  26 + {data.list?.map((dealer: DetailVO = {}) => (
27 27 <div key={`dealer${dealer.settleDealerName}`} style={{ marginTop: 10 }}>
28 28 <div style={{ fontWeight: "bold" }}>{`商家: ${dealer.settleDealerName || ''}`}</div>
29 29 {(dealer.suppliers || []).map((supplier: SupplierVO = {}) => {
... ... @@ -57,6 +57,26 @@ export default function Index({ match }: common.ConnectProps) {
57 57 })}
58 58 </div>
59 59 ))}
  60 + <div style={{ display: 'flex', alignItems: 'flex-start', marginBottom: 20 }}>
  61 + <span style={{ marginRight: 10 }}>备注:{data.remark}</span>
  62 + </div>
  63 + <div style={{ display: 'flex', alignItems: 'flex-start' }}>
  64 + <span style={{ marginRight: 10 }}>附件:</span>
  65 + <div style={{display: 'flex'}}>
  66 + {data.fids?.split(',').map(i => (
  67 + <Upload
  68 + listType="picture-card"
  69 + fileList={[{
  70 + uid: '-1',
  71 + name: i,
  72 + status: 'done',
  73 + url: `/api/file/show?fid=${i}`,
  74 + }]}
  75 + disabled
  76 + />
  77 + ))}
  78 + </div>
  79 + </div>
60 80 <PartDetailModal visible={visiblePart} onCancel={() => setVisiblePart(false)} parts={parts} />
61 81 <StepBnt
62 82 disable={false}
... ...
src/pages/pms/partPlan/PlanPool/api.ts
1 1 import { http } from '@/typing/http';
2 2 import request from '@/utils/request';
3 3 import { PMS_HOST } from '@/utils/host';
  4 +import { PartVO } from '@/pages/pms/partPlan/CustBuyPlan/api';
4 5  
5 6 export interface Params {
6 7 brandId?: number, // 品牌ID
... ... @@ -18,6 +19,7 @@ export interface Params {
18 19  
19 20 export interface ListVO {
20 21 poolId: number; // 计划池id
  22 + poolIds?: string,
21 23 id?: number;
22 24 name?: string; // 名称
23 25 code?: string; // 编码
... ... @@ -61,9 +63,79 @@ export interface ListVO {
61 63 unit?: string; // 采购规格(配件展示)
62 64 splitUnit?: string; // 拆分件规格(配件展示)
63 65 splitCnt?: number; // 拆分件数量(配件展示)
64   - partType?:number
  66 + partType?:number,
  67 + planWaitListIds?:string
65 68 }
66 69  
  70 +export interface OutItem{
  71 + /**
  72 + * 配件ID
  73 + */
  74 +partId?:number;
  75 +/**
  76 + * 配件编码
  77 + */
  78 +partCode?:string;
  79 +/**
  80 + * 配件名称
  81 + */
  82 +partName?:string;
  83 +/**
  84 + * 出库数量
  85 + */
  86 +partCnt?:number;
  87 +/**
  88 + * 成本价
  89 + */
  90 +costPrice?:number;
  91 +/**
  92 + * 出库类型1工单2装潢
  93 + */
  94 +type?:number;
  95 +/**
  96 + * 出库类型ID
  97 + */
  98 +typeId?:string;
  99 +/**
  100 + * 服务站id
  101 + */
  102 +shopId?:number;
  103 +/**
  104 + * 服务站名称
  105 + */
  106 +shopName?:string;
  107 +/**
  108 + * 集团ID
  109 + */
  110 +groupId?:number;
  111 +/**
  112 + * 出库时间
  113 + */
  114 +outTime?:string;
  115 +
  116 +/**
  117 + * 类型名称
  118 + */
  119 +typeName?:string;
  120 +}
  121 +export interface outListVO {
  122 + /**
  123 + * 时间段
  124 + */
  125 + date?: string;
  126 + /**
  127 + * 出库数量
  128 + */
  129 + outCnt?: number;
  130 + /**
  131 + * 最小时间
  132 + */
  133 + min?: string;
  134 + /**
  135 + * 最大时间
  136 + */
  137 + max?: string;
  138 +}
67 139 /**
68 140 * 查询计划池列表
69 141 */
... ... @@ -74,6 +146,19 @@ export function getList(params: Params): http.PromiseResp&lt;ListVO[]&gt; {
74 146 export function deleteApi(params: {poolId: number}) {
75 147 return request.post(`${PMS_HOST}/erp/plan/pool/delete/plan`, {...params});
76 148 }
  149 +
77 150 export function editApi(params: { poolId?: number, partCnt?: number}) {
78 151 return request.post(`${PMS_HOST}/erp/plan/pool/update/plan`, {...params});
79 152 }
  153 +
  154 +export function outFlowApi(params: { poolIds?: any, planId?: number}):http.PromiseResp<outListVO[]> {
  155 + return request.get(`${PMS_HOST}/erp/storage/out/list`, {params});
  156 +}
  157 +
  158 +export function outFlowDetailApi(params:any):http.PromiseResp<OutItem[]> {
  159 + return request.get(`${PMS_HOST}/erp/storage/out/detail`, {params});
  160 +}
  161 +
  162 +export function custBuyApi(params: { planWaitListIds?: any}):http.PromiseResp<PartVO[]> {
  163 + return request.get(`${PMS_HOST}/erp/cus/buy/part/get/buy/part/list`, {params});
  164 +}
... ...
src/pages/pms/partPlan/PlanPool/components/AreaTable.tsx
... ... @@ -4,6 +4,7 @@ import useInitial from &quot;@/hooks/useInitail&quot;;
4 4 import {getList, ListVO} from "@/pages/pms/partPlan/PlanPool/api";
5 5 import DetailModal from './DetailModal';
6 6 import {useStore} from "@/pages/pms/partPlan/PlanPool";
  7 +import _ from 'lodash';
7 8  
8 9 const { Column } = Table;
9 10 interface Props {
... ... @@ -14,7 +15,7 @@ interface Props {
14 15 id?: number, // 上一个列表ID
15 16 }
16 17 export default function Index(props: Props = {}) {
17   - const { dfParams, key } = useStore();
  18 + const { dfParams, key, setItem, setOutVisible, setCustVisible } = useStore();
18 19 const {showAnalyse=true} = props;
19 20 const { data: parts, setParams, loading } = useInitial(getList, [], {...dfParams, ...props});
20 21 const [visible, setVisible] = useState(false);
... ... @@ -23,7 +24,6 @@ export default function Index(props: Props = {}) {
23 24 const [id, setId] = useState<number>();
24 25  
25 26 useEffect(() => {
26   - console.log('dfParams11', dfParams, key, props);
27 27 if (key == props.type) {
28 28 setParams(dfParams, true);
29 29 }
... ... @@ -34,16 +34,16 @@ export default function Index(props: Props = {}) {
34 34 <Table rowKey={(v: ListVO) => `${v.id}`} scroll={{y: 500, x: 2500}} dataSource={parts || []} pagination={false} loading={loading}>
35 35 <Column title="区域库" dataIndex="name" fixed="left" />
36 36 <Column title="本次计划数量(个)" dataIndex="cnt" fixed="left" />
37   - <Column title="计划前库销比" dataIndex="ratio" render={t => (t || 0).toFixed(2)} />
38   - <Column title="计划后库销比" dataIndex="planeRatio" render={t => (t || 0).toFixed(2)} />
  37 + <Column title="计划前库销比" dataIndex="ratio" render={t => (t ? t.toFixed(2) : "--")} />
  38 + <Column title="计划后库销比" dataIndex="planRatio" render={t => (t ? t.toFixed(2) : "--")} />
39 39 <Column title="本次计划金额(元)" dataIndex="thisTimeAmount" />
40   - <Column title="客户订件数量(个)" dataIndex="buyCnt" />
  40 + <Column title="客户订件数量(个)" render={r => (r.buyCnt ? <a onClick={() => { setCustVisible(true); setItem(r); }}>{r.buyCnt}</a> : r.buyCnt)} />
41 41 <Column title="客户订件金额(元)" dataIndex="buyAmount" />
42 42 <Column title="在途未锁(个)" dataIndex="onTheWayUnlockCnt" />
43 43  
44 44 <Column title="在库未锁(个)" dataIndex="storageUnlockCnt" />
45 45 <Column title="在库已锁(个)" dataIndex="storageLockedCnt" />
46   - <Column title="滚动90天出库(个)" dataIndex="outStockCnt" />
  46 + <Column title="近90天月均出库(个)" render={r => (r.outStockCnt ? <a onClick={() => { setOutVisible(true); setItem(r); }}>{_.floor(r.outStockCnt/3)}</a> : r.outStockCnt)} />
47 47 {showAnalyse && (
48 48 <>
49 49 <Column
... ...
src/pages/pms/partPlan/PlanPool/components/CustBuyModal.tsx 0 → 100644
  1 +import React, { useEffect, useState } from 'react';
  2 +import { Button, Modal, Table } from 'antd';
  3 +import { useStore } from '../index';
  4 +import { custBuyApi } from '../api';
  5 +import { PartVO } from '@/pages/pms/partPlan/CustBuyPlan/api';
  6 +import useInitial from '@/hooks/useInitail';
  7 +
  8 +const { Column } = Table;
  9 +
  10 +export default function Index() {
  11 + const { custVisible, setCustVisible, item } = useStore();
  12 + const [delay, setDelay] = useState(true);
  13 + const { data, setParams, loading } = useInitial(custBuyApi, [], {}, delay);
  14 +
  15 + useEffect(() => {
  16 + if (custVisible && item?.planWaitListIds) {
  17 + setParams({ planWaitListIds: item.planWaitListIds }, true);
  18 + setDelay(false);
  19 + }
  20 + }, [custVisible]);
  21 +
  22 + return (
  23 + <Modal
  24 + title="客户订件详情"
  25 + width={1100}
  26 + visible={custVisible}
  27 + maskClosable={false}
  28 + onCancel={() => setCustVisible(false)}
  29 + footer={[
  30 + <Button onClick={() => setCustVisible(false)}>取消</Button>
  31 + ]}
  32 + >
  33 + <Table
  34 + rowKey={(v: PartVO) => `${v.waitListIds}`}
  35 + dataSource={data}
  36 + pagination={false}
  37 + loading={loading}
  38 + scroll={{x: 1400, y: 500}}
  39 + >
  40 + <Column title="时间" dataIndex="planTime" />
  41 + <Column title="VIN" dataIndex="typeId" />
  42 + <Column title="工单号" dataIndex="remark" />
  43 + <Column title="车牌号" dataIndex="plateNo" />
  44 + <Column title="配件编码" dataIndex="partCode" />
  45 + <Column title="配件名称" dataIndex="partName" />
  46 + <Column title="接车服务顾问" dataIndex="userName" />
  47 + <Column title="门店名称" dataIndex="shopName" />
  48 + <Column title="库房名称" dataIndex="storageName" />
  49 + <Column title="订件数量" dataIndex="splitCnt" />
  50 + <Column title="采购单价" dataIndex="price" />
  51 + <Column title="采购数量" dataIndex="cnt" />
  52 + </Table>
  53 + </Modal>
  54 + );
  55 +}
0 56 \ No newline at end of file
... ...
src/pages/pms/partPlan/PlanPool/components/OutFlowDetailModal.tsx 0 → 100644
  1 +import React, { useEffect, useState } from 'react';
  2 +import { Button, Modal, Table } from 'antd';
  3 +import { outFlowDetailApi, OutItem } from '../api';
  4 +import useInitial from '@/hooks/useInitail';
  5 +import moment from 'moment';
  6 +
  7 +const { Column } = Table;
  8 +interface Props {
  9 + visible?:boolean
  10 + setVisible:Function
  11 + item?:any
  12 +}
  13 +export default function Index(props:Props) {
  14 + const { visible, setVisible, item } = props;
  15 + const [delay, setDelay] = useState(true);
  16 + const { data, setParams, loading } = useInitial(outFlowDetailApi, [], {}, delay);
  17 +
  18 + useEffect(() => {
  19 + if (visible && item?.poolIds) {
  20 + setParams({ min: undefined, max: undefined, date: undefined, outCnt: undefined, ...item }, true);
  21 + setDelay(false);
  22 + } else {
  23 + setVisible();
  24 + }
  25 + }, [visible]);
  26 +
  27 + return (
  28 + <Modal
  29 + title="出库详情"
  30 + width={1000}
  31 + visible={visible}
  32 + maskClosable={false}
  33 + onCancel={() => setVisible()}
  34 + footer={[
  35 + <Button onClick={() => setVisible()}>取消</Button>
  36 + ]}
  37 + >
  38 + <Table
  39 + dataSource={data}
  40 + loading={loading}
  41 + rowKey={(v: OutItem) => `${v.partId}`}
  42 + pagination={false}
  43 + scroll={{ y: 400 }}
  44 + >
  45 + <Column title="配件名称" dataIndex="partName" />
  46 + <Column title="配件编码" dataIndex="partCode" />
  47 + <Column title="出库数量" dataIndex="partCnt" />
  48 + <Column title="出库类型" dataIndex="typeName" />
  49 + <Column title="服务站名称" dataIndex="shopName" />
  50 + <Column title="出库时间" render={r => moment(r.outTime).format('YYYY-MM-DD HH:mm:ss')} />
  51 + </Table>
  52 + </Modal>
  53 + );
  54 +}
0 55 \ No newline at end of file
... ...
src/pages/pms/partPlan/PlanPool/components/OutFlowModal.tsx 0 → 100644
  1 +import React, { useEffect, useState } from 'react';
  2 +import {Button, Modal, Table} from 'antd';
  3 +import {useStore} from '../index';
  4 +import { outFlowApi, outListVO } from '../api';
  5 +import useInitial from '@/hooks/useInitail';
  6 +import OutFlowDetailModal from './OutFlowDetailModal';
  7 +
  8 +const {Column} = Table;
  9 +
  10 +export default function Index() {
  11 + const {outVisible, setOutVisible, item} = useStore();
  12 + const [delay, setDelay]= useState(true);
  13 + const { data, setParams, loading } = useInitial(outFlowApi, [], {}, delay);
  14 + const [current, setCurrent] = useState<{visible?: boolean, itemData?: any}>();
  15 +
  16 + useEffect(() => {
  17 + if (outVisible && item?.poolIds) {
  18 + setParams({poolIds: item.poolIds}, true);
  19 + setDelay(false);
  20 + }
  21 + }, [outVisible]);
  22 + const total = data
  23 + .map(i => i.outCnt)
  24 + .reduce((prev, cur) => {
  25 + return (prev || 0) + (cur || 0);
  26 + }, 0);
  27 +
  28 + return (
  29 + <Modal
  30 + title={`${item?.partName}滚动90天出库流水`}
  31 + width={1000}
  32 + visible={outVisible}
  33 + maskClosable={false}
  34 + onCancel={() => setOutVisible(false)}
  35 + footer={[
  36 + <Button onClick={() => setOutVisible(false)}>取消</Button>
  37 + ]}
  38 + >
  39 + <div style={{marginBottom: 20}}>
  40 + 滚动90天出库数:
  41 + <span
  42 + style={{ color: '#0000FF', cursor: 'pointer' }}
  43 + onClick={() => setCurrent({ visible: true, itemData: { poolIds: item?.poolIds } })}
  44 + >
  45 + {total}
  46 + </span>
  47 + </div>
  48 + <Table
  49 + dataSource={data}
  50 + loading={loading}
  51 + rowKey={(v: outListVO) => `${v.date}`}
  52 + pagination={false}
  53 + scroll={{y: 400}}
  54 + >
  55 + <Column title="出库日期" dataIndex="date" />
  56 + <Column title="出库数量" render={r => <a onClick={() => setCurrent({ visible: true, itemData: { ...r, poolIds: item?.poolIds }})}>{r.outCnt}</a>} />
  57 + </Table>
  58 + <OutFlowDetailModal visible={current?.visible} setVisible={() => setCurrent({visible: false, itemData: undefined})} item={current?.itemData} />
  59 + </Modal>
  60 + );
  61 +}
0 62 \ No newline at end of file
... ...
src/pages/pms/partPlan/PlanPool/components/PartTable.tsx
... ... @@ -4,6 +4,7 @@ import useInitial from &quot;@/hooks/useInitail&quot;;
4 4 import {getList, ListVO} from "@/pages/pms/partPlan/PlanPool/api";
5 5 import DetailModal from './DetailModal';
6 6 import {useStore} from "@/pages/pms/partPlan/PlanPool";
  7 +import _ from 'lodash';
7 8  
8 9 const { Column } = Table;
9 10 interface Props {
... ... @@ -16,7 +17,7 @@ interface Props {
16 17 id?: number, // 上一个列表ID
17 18 }
18 19 export default function Index(props: Props = {}) {
19   - const { dfParams, key } = useStore();
  20 + const { dfParams, key, setItem, setOutVisible, setCustVisible } = useStore();
20 21 const {showAnalyse=true} = props;
21 22 const { data: parts, setParams, loading } = useInitial(getList, [], {...dfParams, ...props});
22 23 const [visible, setVisible] = useState(false);
... ... @@ -39,17 +40,17 @@ export default function Index(props: Props = {}) {
39 40 <Column title="来源类型" dataIndex="typeName" />
40 41 <Column title="配件类型" dataIndex="partTypeName" />
41 42  
42   - <Column title="计划前库销比" dataIndex="ratio" render={t => (t || 0).toFixed(2)} />
43   - <Column title="计划后库销比" dataIndex="planeRatio" render={t => (t || 0).toFixed(2)} />
  43 + <Column title="计划前库销比" dataIndex="ratio" render={t => (t ? t.toFixed(2) : "--")} />
  44 + <Column title="计划后库销比" dataIndex="planRatio" render={t => (t ? t.toFixed(2) : "--")} />
44 45  
45 46 <Column title="本次计划金额(元)" dataIndex="thisTimeAmount" />
46   - <Column title="客户订件数量(个)" dataIndex="buyCnt" />
  47 + <Column title="客户订件数量(个)" render={r => (r.buyCnt ? <a onClick={() => { setCustVisible(true); setItem(r); }}>{r.buyCnt}</a> : r.buyCnt)} />
47 48 <Column title="客户订件金额(元)" dataIndex="buyAmount" />
48 49 <Column title="在途未锁(个)" dataIndex="onTheWayUnlockCnt" />
49 50  
50 51 <Column title="在库未锁(个)" dataIndex="storageUnlockCnt" />
51 52 <Column title="在库已锁(个)" dataIndex="storageLockedCnt" />
52   - <Column title="滚动90天出库(个)" dataIndex="outStockCnt" />
  53 + <Column title="近90天月均出库(个)" render={r => (r.outStockCnt ? <a onClick={() => { setOutVisible(true); setItem(r); }}>{_.floor(r.outStockCnt/3)}</a> : r.outStockCnt)} />
53 54 {showAnalyse && (
54 55 <>
55 56 <Column
... ...
src/pages/pms/partPlan/PlanPool/components/SeriesTable.tsx
... ... @@ -4,6 +4,7 @@ import useInitial from &quot;@/hooks/useInitail&quot;;
4 4 import {getList, ListVO} from "@/pages/pms/partPlan/PlanPool/api";
5 5 import DetailModal from './DetailModal';
6 6 import {useStore} from "@/pages/pms/partPlan/PlanPool";
  7 +import _ from 'lodash';
7 8  
8 9 const { Column } = Table;
9 10 interface Props {
... ... @@ -15,7 +16,7 @@ interface Props {
15 16 id?: number, // 上一个列表ID
16 17 }
17 18 export default function Index(props: Props = {}) {
18   - const { dfParams, key } = useStore();
  19 + const { dfParams, key, setItem, setOutVisible, setCustVisible } = useStore();
19 20 const {showAnalyse=true} = props;
20 21 const { data: parts, setParams, loading } = useInitial(getList, [], {...dfParams, ...props});
21 22 const [visible, setVisible] = useState(false);
... ... @@ -34,17 +35,17 @@ export default function Index(props: Props = {}) {
34 35 <Table rowKey={(v: ListVO) => `${v.id}`} scroll={{y: 500, x: 2500}} dataSource={parts || []} pagination={false} loading={loading}>
35 36 <Column title="车系" dataIndex="name" fixed="left" />
36 37 <Column title="本次计划数量(个)" dataIndex="cnt" fixed="left" />
37   - <Column title="计划前库销比" dataIndex="ratio" render={t => (t || 0).toFixed(2)} />
38   - <Column title="计划后库销比" dataIndex="planeRatio" render={t => (t || 0).toFixed(2)} />
  38 + <Column title="计划前库销比" dataIndex="ratio" render={t => (t ? t.toFixed(2) : "--")} />
  39 + <Column title="计划后库销比" dataIndex="planRatio" render={t => (t ? t.toFixed(2) : "--")} />
39 40  
40 41 <Column title="本次计划金额(元)" dataIndex="thisTimeAmount" />
41   - <Column title="客户订件数量(个)" dataIndex="buyCnt" />
  42 + <Column title="客户订件数量(个)" render={r => (r.buyCnt ? <a onClick={() => { setCustVisible(true); setItem(r); }}>{r.buyCnt}</a> : r.buyCnt)} />
42 43 <Column title="客户订件金额(元)" dataIndex="buyAmount" />
43 44 <Column title="在途未锁(个)" dataIndex="onTheWayUnlockCnt" />
44 45  
45 46 <Column title="在库未锁(个)" dataIndex="storageUnlockCnt" />
46 47 <Column title="在库已锁(个)" dataIndex="storageLockedCnt" />
47   - <Column title="滚动90天出库(个)" dataIndex="outStockCnt" />
  48 + <Column title="近90天月均出库(个)" render={r => (r.outStockCnt ? <a onClick={() => { setOutVisible(true); setItem(r); }}>{_.floor(r.outStockCnt/3)}</a> : r.outStockCnt)} />
48 49 {showAnalyse && (
49 50 <>
50 51 <Column
... ...
src/pages/pms/partPlan/PlanPool/components/StoragePartTable.tsx
... ... @@ -4,6 +4,7 @@ import useInitial from &quot;@/hooks/useInitail&quot;;
4 4 import {getList, ListVO} from "@/pages/pms/partPlan/PlanPool/api";
5 5 import {useStore} from "@/pages/pms/partPlan/PlanPool";
6 6 import {deleteApi, editApi} from '../api';
  7 +import _ from 'lodash';
7 8  
8 9 const { Column } = Table;
9 10 const {Item} = Form;
... ... @@ -12,11 +13,11 @@ interface Props {
12 13 type?: number, // 类型1区域库2库房3车系4车型5配件
13 14 }
14 15 export default function Index(props: Props = {}) {
15   - const { dfParams, key } = useStore();
  16 + const { dfParams, key, setItem, setOutVisible, setCustVisible } = useStore();
16 17 const [form] = Form.useForm();
17 18 const { data: parts, setParams, loading } = useInitial(getList, [], dfParams);
18 19 const [visible, setVisible] = useState(false);
19   - const [item, setItem] = useState<ListVO>();
  20 + const [itemPrice, setItemPrice] = useState<ListVO>();
20 21  
21 22 useEffect(() => {
22 23 if (key == props.type) {
... ... @@ -25,8 +26,8 @@ export default function Index(props: Props = {}) {
25 26 }, [dfParams, key]);
26 27  
27 28 useEffect(() => {
28   - if (visible && item?.poolId) {
29   - form.setFieldsValue({cnt: item.cnt});
  29 + if (visible && itemPrice?.poolId) {
  30 + form.setFieldsValue({ cnt: itemPrice.cnt});
30 31 } else {
31 32 form.resetFields;
32 33 }
... ... @@ -43,7 +44,7 @@ export default function Index(props: Props = {}) {
43 44 fixed="left"
44 45 render={r => (
45 46 <>
46   - <a onClick={() => { setVisible(true); setItem(r); }}>编辑</a>
  47 + <a onClick={() => { setVisible(true); setItemPrice(r); }}>编辑</a>
47 48 <Divider type="vertical" />
48 49 <Popconfirm
49 50 title="确认删除?"
... ... @@ -64,16 +65,16 @@ export default function Index(props: Props = {}) {
64 65 <Column title="来源类型" dataIndex="typeName" />
65 66 <Column title="配件类型" dataIndex="partTypeName" />
66 67  
67   - <Column title="计划前库销比" dataIndex="ratio" render={t => (t || 0).toFixed(2)} />
68   - <Column title="计划后库销比" dataIndex="planeRatio" render={t => (t || 0).toFixed(2)} />
  68 + <Column title="计划前库销比" dataIndex="ratio" render={t => (t ? t.toFixed(2) : "--")} />
  69 + <Column title="计划后库销比" dataIndex="planRatio" render={t => (t ? t.toFixed(2) : "--")} />
69 70  
70 71 <Column title="本次计划金额(元)" dataIndex="thisTimeAmount" />
71   - <Column title="客户订件数量(个)" dataIndex="buyCnt" />
  72 + <Column title="客户订件数量(个)" render={r => (r.buyCnt ? <a onClick={() => { setCustVisible(true); setItem(r); }}>{r.buyCnt}</a> : r.buyCnt)} />
72 73 <Column title="客户订件金额(元)" dataIndex="buyAmount" />
73 74 <Column title="在途未锁(个)" dataIndex="onTheWayUnlockCnt" />
74 75 <Column title="在库未锁(个)" dataIndex="storageUnlockCnt" />
75 76 <Column title="在库已锁(个)" dataIndex="storageLockedCnt" />
76   - <Column title="滚动90天出库(个)" dataIndex="outStockCnt" />
  77 + <Column title="近90天月均出库(个)" render={r => (r.outStockCnt ? <a onClick={() => { setOutVisible(true); setItem(r); }}>{_.floor(r.outStockCnt/3)}</a> : r.outStockCnt)} />
77 78  
78 79 </Table>
79 80 <Modal
... ... @@ -90,7 +91,7 @@ export default function Index(props: Props = {}) {
90 91 htmlType="submit"
91 92 onClick={() => {
92 93 form.validateFields().then(fields => {
93   - editApi({poolId: item?.poolId, partCnt: fields.cnt}).then(res => {
  94 + editApi({ poolId: itemPrice?.poolId, partCnt: fields.cnt}).then(res => {
94 95 setVisible(false);
95 96 message.success("操作成功");
96 97 setParams({}, true);
... ...
src/pages/pms/partPlan/PlanPool/components/StorageTable.tsx
... ... @@ -4,6 +4,7 @@ import useInitial from &quot;@/hooks/useInitail&quot;;
4 4 import {getList, ListVO} from "@/pages/pms/partPlan/PlanPool/api";
5 5 import DetailModal from './DetailModal';
6 6 import {useStore} from "@/pages/pms/partPlan/PlanPool";
  7 +import {floor} from 'lodash';
7 8  
8 9 const { Column } = Table;
9 10 interface Props {
... ... @@ -14,7 +15,7 @@ interface Props {
14 15 id?: number, // 上一个列表ID
15 16 }
16 17 export default function Index(props: Props = {}) {
17   - const { dfParams, key } = useStore();
  18 + const { dfParams, key, setItem, setOutVisible, setCustVisible } = useStore();
18 19 const {showAnalyse=true} = props;
19 20 const { data: parts, setParams, loading } = useInitial(getList, [], {...dfParams, ...props});
20 21 const [visible, setVisible] = useState(false);
... ... @@ -33,16 +34,16 @@ export default function Index(props: Props = {}) {
33 34 <Table rowKey={(v: ListVO) => `${v.id}`} scroll={{y: 500, x: 2500}} dataSource={parts || []} pagination={false} loading={loading}>
34 35 <Column title="库房" dataIndex="name" fixed="left" />
35 36 <Column title="本次计划数量(个)" dataIndex="cnt" fixed="left" />
36   - <Column title="计划前库销比" dataIndex="ratio" render={t => (t || 0).toFixed(2)} />
37   - <Column title="计划后库销比" dataIndex="planeRatio" render={t => (t || 0).toFixed(2)} />
  37 + <Column title="计划前库销比" dataIndex="ratio" render={t => (t ? t.toFixed(2) : "--")} />
  38 + <Column title="计划后库销比" dataIndex="planRatio" render={t => (t ? t.toFixed(2) : "--")} />
38 39  
39 40 <Column title="本次计划金额(元)" dataIndex="thisTimeAmount" />
40   - <Column title="客户订件数量(个)" dataIndex="buyCnt" />
  41 + <Column title="客户订件数量(个)" render={r => (r.buyCnt ? <a onClick={() => { setCustVisible(true); setItem(r); }}>{r.buyCnt}</a> : r.buyCnt)} />
41 42 <Column title="客户订件金额(元)" dataIndex="buyAmount" />
42 43 <Column title="在途未锁(个)" dataIndex="onTheWayUnlockCnt" />
43 44 <Column title="在库未锁(个)" dataIndex="storageUnlockCnt" />
44 45 <Column title="在库已锁(个)" dataIndex="storageLockedCnt" />
45   - <Column title="滚动90天出库(个)" dataIndex="outStockCnt" />
  46 + <Column title="近90天月均出库(个)" render={r => (r.outStockCnt ? <a onClick={() => { setOutVisible(true); setItem(r); }}>{floor(r.outStockCnt/3)}</a> : r.outStockCnt)} />
46 47 {showAnalyse && (
47 48 <>
48 49 <Column
... ...
src/pages/pms/partPlan/PlanPool/index.tsx
... ... @@ -11,6 +11,8 @@ import st from &quot;@/pages/pms/partPlan/PlanShipping/style.less&quot;;
11 11 import Filter from './components/Filter';
12 12 import {createStore} from "@/hooks/moz";
13 13 import store from "./useStore";
  14 +import OutFlowModal from './components/OutFlowModal';
  15 +import CustBuyModal from './components/CustBuyModal';
14 16  
15 17 export const { Provider, useStore } = createStore(store);
16 18  
... ... @@ -38,6 +40,8 @@ function Index() {
38 40 <StoragePartTable type={6} />
39 41 </Tabs.TabPane>
40 42 </Tabs>
  43 + <OutFlowModal />
  44 + <CustBuyModal />
41 45 </Card>
42 46 </ConfigProvider>
43 47 </PageHeaderWrapper>
... ...
src/pages/pms/partPlan/PlanPool/useStore.ts
1 1 import { useState } from 'react';
2 2 import useInitail from "@/hooks/useInitail";
3 3 import { getPartTypeApi } from '@/pages/pms/part/Repertory/api';
  4 +import {ListVO} from './api';
4 5  
5 6 export default function useStore() {
6 7 const [dfParams, setDfParams] = useState<any>({});
7 8 const [key, setKey] = useState<any>('1');
8 9 const { data: partTypeData } = useInitail(getPartTypeApi, [], {});
  10 + const [outVisible, setOutVisible] = useState(false);
  11 + const [custVisible, setCustVisible] = useState(false);
  12 + const [item, setItem] = useState<ListVO>();
9 13  
10 14 return {
11 15 dfParams,
12 16 setDfParams,
13 17 key,
14 18 setKey,
15   - partTypeData
  19 + partTypeData,
  20 + outVisible,
  21 + setOutVisible,
  22 + item,
  23 + setItem,
  24 + custVisible,
  25 + setCustVisible,
16 26 };
17 27 }
... ...
src/pages/pms/storage/partShop/api.ts
... ... @@ -42,6 +42,12 @@ export function getLockDetail(params?: PmsStoragePartShop.LockParams): http.Prom
42 42 export function getFlowDetail(params?: PmsStoragePartShop.FlowParams): http.PromisePageResp<PmsStoragePartShop.FlowVO> {
43 43 return request.get(`${PMS_HOST}/erp/part/shop/get/record`, { params });
44 44 }
  45 +/**
  46 + * 查询门店备件锁库流水明细列表
  47 + */
  48 +export function getLockFlowDetail(params?: PmsStoragePartShop.FlowParams): http.PromisePageResp<PmsStoragePartShop.FlowVO> {
  49 + return request.get(`${PMS_HOST}/erp/part/shop/get/lock/record`, { params });
  50 +}
45 51 // 释放库存
46 52 export function unLock(params: PmsStoragePartShop.unLock): http.PromiseResp<string> {
47 53 return request.post(`${PMS_HOST}/erp/part/shop/cancel/lock`, { ...params }, { contentType: "form-urlencoded" });
... ...
src/pages/pms/storage/partShop/components/Filter.tsx
... ... @@ -32,14 +32,14 @@ export default function Filter() {
32 32 return (
33 33 <div>
34 34 <Search
35   - style={{ width: 200, marginRight: 10 }}
  35 + style={{ width: 180, marginRight: 10, marginBottom: 10 }}
36 36 allowClear
37 37 enterButton
38 38 placeholder="配件编码|名称"
39 39 onSearch={v => handleChangeKeywords(v)}
40 40 />
41 41 <PmsSelect
42   - style={{ width: 180, marginRight: 10}}
  42 + style={{ width: 180, marginRight: 10, marginBottom: 10 }}
43 43 allowClear
44 44 value={innerParams.shopId}
45 45 onChange={value => {
... ... @@ -52,7 +52,7 @@ export default function Filter() {
52 52 .map((item: PmsStoragePartShop.Option) => ({value: item.id, label: item.name}))}
53 53 />
54 54 <PmsSelect
55   - style={{ width: 150, marginRight: 10}}
  55 + style={{ width: 180, marginRight: 10, marginBottom: 10 }}
56 56 allowClear
57 57 value={innerParams.storageId}
58 58 onChange={value => {
... ... @@ -66,7 +66,7 @@ export default function Filter() {
66 66 />
67 67 <PmsSelect
68 68 allowClear
69   - style={{ width: 150, marginRight: 10}}
  69 + style={{ width: 180, marginRight: 10, marginBottom: 10 }}
70 70 onChange={(type) => {
71 71 setParams({ ...innerParams, current: 1, type }, true);
72 72 }}
... ... @@ -77,7 +77,7 @@ export default function Filter() {
77 77 allowClear
78 78 placeholder="有无库存筛选"
79 79 onChange={v => isStock(v)}
80   - style={{ width: 150, marginRight: 10 }}
  80 + style={{ width: 180, marginRight: 10, marginBottom: 10 }}
81 81 options={[
82 82 {value: 1, label: "有库存"},
83 83 {value: 0, label: "无库存"},
... ... @@ -87,7 +87,7 @@ export default function Filter() {
87 87 placeholder="排序方式"
88 88 defaultValue={18}
89 89 onChange={v => isSorter(v)}
90   - style={{ width: 150 }}
  90 + style={{ width: 180 }}
91 91 options={[
92 92 {value: 18, label: "总库存降序"},
93 93 {value: 21, label: "锁定库存降序"},
... ...
src/pages/pms/storage/partShop/components/List.tsx
... ... @@ -4,6 +4,7 @@ import { useStore } from &#39;../index&#39;;
4 4 import LockDetailModal from './LockDetailModal';
5 5 import FlowDetailModal from './FlowDetailModal';
6 6 import PartShopModal from './PartShopModal';
  7 +import LockFlowModal from './LockFlowModal';
7 8  
8 9 const { Column } = Table;
9 10  
... ... @@ -11,6 +12,7 @@ export default function Filter() {
11 12 const { setParams, loading, paginationConfig, list, setVisible, setItem, item, fw, setIsprice} = useStore();
12 13 const [visibleLockDetail, setVisibleLockDetail] = useState(false);
13 14 const [visibleFlowDetail, setVisibleFlowDetail] = useState(false);
  15 + const [visibleLockFlow, setVisibleLockFlow] = useState(false);
14 16  
15 17 return (
16 18 <div>
... ... @@ -43,6 +45,14 @@ export default function Filter() {
43 45 title="入库流水"
44 46 render={(t, it: PartRepertorySpace.Item) => <a onClick={() => { setVisibleFlowDetail(true); setItem({...it, isOut: false}); }}>查看</a>}
45 47 />
  48 + <Column
  49 + title="锁库流水"
  50 + render={(t, it: PartRepertorySpace.Item) => <a onClick={() => { setVisibleLockFlow(true); setItem({...it, isLock: true}); }}>查看</a>}
  51 + />
  52 + <Column
  53 + title="释放流水"
  54 + render={(t, it: PartRepertorySpace.Item) => <a onClick={() => { setVisibleLockFlow(true); setItem({...it, isLock: false}); }}>查看</a>}
  55 + />
46 56 {fw ? (
47 57 <Column
48 58 title="操作"
... ... @@ -65,6 +75,7 @@ export default function Filter() {
65 75 </Table>
66 76 <LockDetailModal item={item} visible={visibleLockDetail} onCancel={() => setVisibleLockDetail(false)} />
67 77 <FlowDetailModal item={item} visible={visibleFlowDetail} onCancel={() => setVisibleFlowDetail(false)} />
  78 + <LockFlowModal item={item} visible={visibleLockFlow} onCancel={() => setVisibleLockFlow(false)} />
68 79 <PartShopModal />
69 80 </div>
70 81 );
... ...
src/pages/pms/storage/partShop/components/LockFlowModal.tsx 0 → 100644
  1 +import React, {useEffect, useState} from 'react';
  2 +import {Modal, Table, Button} from 'antd';
  3 +import { getLockFlowDetail } from '@/pages/pms/storage/partShop/api';
  4 +import usePagination from '@/hooks/usePagination';
  5 +
  6 +interface Props {
  7 + item?: any
  8 + visible: boolean
  9 + onCancel: () => any
  10 +}
  11 +const {Column} = Table;
  12 +export default function Index(props: Props) {
  13 + const {item, visible, onCancel} = props;
  14 + const [delay, setDelay] = useState(true);
  15 + const { list, loading, setParams, paginationConfig, setList } = usePagination<PmsStoragePartShop.FlowVO>(getLockFlowDetail, {}, { delay });
  16 +
  17 + useEffect(() => {
  18 + if (item.shopId && item.partId && visible) {
  19 + setParams({ partId: item.partId, shopId: item.shopId, isLock: item.isLock }, true);
  20 + setDelay(false);
  21 + } else {
  22 + setList([]);
  23 + }
  24 + }, [visible, item.partId]);
  25 +
  26 + return (
  27 + <Modal
  28 + title={`${item.isLock ? '锁定库存' : '释放库存'}流水`}
  29 + width={1000}
  30 + visible={visible}
  31 + maskClosable={false}
  32 + onCancel={onCancel}
  33 + footer={[
  34 + <Button key="1" onClick={onCancel}>取消</Button>,
  35 + ]}
  36 + >
  37 + <Table
  38 + loading={loading}
  39 + dataSource={list}
  40 + rowKey={(v: PmsStoragePartShop.FlowVO) => `${v.type}_${v.typeId}`}
  41 + pagination={paginationConfig}
  42 + >
  43 + <Column title="配件数量" dataIndex="partCnt" />
  44 + <Column title="单号" dataIndex="remark" render={t => t || "--"} />
  45 + <Column
  46 + title="详情"
  47 + dataIndex="text"
  48 + width={350}
  49 + render={(t: string, it: PmsStoragePartShop.FlowVO) => {
  50 + const obj = JSON.parse(t || '{}');
  51 + return (
  52 + <div>
  53 + {!!obj.type && <div>{`类型: ${obj.type}`}</div>}
  54 + {!!obj.serviceCatName && <div>{`进站类型: ${obj.serviceCatName}`}</div>}
  55 + {!!obj.exclusiveAdviser && <div>{`专属顾问: ${obj.exclusiveAdviser}`}</div>}
  56 + {!!obj.shopLinkmanName && <div>{`服务顾问: ${obj.shopLinkmanName}`}</div>}
  57 + {!!obj.receiverName && <div>{`服务顾问: ${obj.receiverName}`}</div>}
  58 + {!!obj.plateNo && <div>{`车牌号: ${obj.plateNo}`}</div>}
  59 + {!!obj.ownerName && <div>{`车主: ${obj.ownerName}`}</div>}
  60 + {!!obj.vin && <div>{`VIN: ${obj.vin}`}</div>}
  61 + {!!obj.userName && <div>{`操作账号: ${obj.userName}`}</div>}
  62 + {!!obj.fixRemark && <div>{`备注: ${obj.fixRemark}`}</div>}
  63 + </div>
  64 + );
  65 + }}
  66 + />
  67 + <Column title={`${item.isLock ? '锁库' : '释放'}时间`} dataIndex="recordTime" />
  68 + </Table>
  69 + </Modal>
  70 + );
  71 +}
0 72 \ No newline at end of file
... ...
src/pages/pms/storage/partShop/components/PartShopModal.tsx
... ... @@ -29,7 +29,7 @@ export default function PartShopModal() {
29 29 });
30 30 }
31 31 }, [visible]);
32   -
  32 +
33 33 useEffect(() => {
34 34 if (isadd) {
35 35 setItem({});
... ... @@ -119,7 +119,7 @@ export default function PartShopModal() {
119 119 <InputNumber style={{ width: "100%" }} min={0} step={1} placeholder="总库存数量" disabled={isprice || isadd} />
120 120 </Item>
121 121 <Item label="锁定库存" name="lockStock" rules={[{ required: true, message: "请输入锁定库存" }, { validator: validatorLockStock }]}>
122   - <InputNumber style={{ width: "100%" }} min={0} step={1} placeholder="锁定库存" disabled={isprice || isadd} />
  122 + <InputNumber style={{ width: "100%" }} min={0} step={1} placeholder="锁定库存" disabled />
123 123 </Item>
124 124 {!!fw && !isprice && !isadd && (
125 125 <Item label="修改人" name="user" rules={[{ required: true, message: "请输入修改人" }]}>
... ...
src/pages/pms/storage/partShop/index.tsx
1 1 import React, {useState} from 'react';
2   -import { PlusOutlined, VerticalAlignBottomOutlined } from '@ant-design/icons';
  2 +import { PlusOutlined, DownloadOutlined, UploadOutlined } from '@ant-design/icons';
3 3 import { Card, Button } from 'antd';
4 4 import { PageHeaderWrapper } from '@ant-design/pro-layout';
5 5 import Filter from './components/Filter';
... ... @@ -20,53 +20,51 @@ function PartShop() {
20 20 return (
21 21 <PageHeaderWrapper title={`服务站配件${fw ? '(霏微)': ''}`}>
22 22 <Card>
23   - <div style={{ display: 'flex', flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginBottom: 20 }}>
  23 + <div style={{ display: 'flex', flexDirection: 'row', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: 20 }}>
24 24 <Filter />
25   - <div style={{display: 'flex', flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center'}}>
  25 + <div style={{ display: 'flex', alignItems: 'center'}}>
  26 + <Button
  27 + type="primary"
  28 + icon={<PlusOutlined />}
  29 + onClick={() => { setVisible(true); setIsadd(true); }}
  30 + >
  31 + 新增
  32 + </Button>
26 33 {fw && (
27   - <>
28   - <Button
29   - icon={(<PlusOutlined />)}
30   - type="primary"
31   - onClick={() => setImportVisible(true)}
32   - >
33   - 导入
34   - </Button>
35   - <Button
36   - icon={(<PlusOutlined />)}
37   - type="primary"
38   - onClick={() => { setImportVisible(true); setStock(true); }}
39   - style={{marginLeft: 10}}
40   - >
41   - 调运库存导入
42   - </Button>
43   - </>
44   - )}
45   - {/* {!fw && ( */}
46 34 <Button
  35 + icon={<UploadOutlined />}
47 36 type="primary"
48   - icon={<VerticalAlignBottomOutlined />}
49   - onClick={() => { setMore(true); setIslock(true); }}
  37 + onClick={() => setImportVisible(true)}
  38 + style={{ marginLeft: 10 }}
  39 + >
  40 + 导入
  41 + </Button>
  42 + )}
  43 + {fw && (
  44 + <Button
  45 + icon={<UploadOutlined />}
  46 + type="primary"
  47 + onClick={() => { setImportVisible(true); setStock(true); }}
50 48 style={{marginLeft: 10}}
51 49 >
52   - 锁件批量导出
  50 + 调运库存导入
53 51 </Button>
54   - {/* )} */}
  52 + )}
55 53 <Button
56 54 type="primary"
57   - icon={<VerticalAlignBottomOutlined />}
58   - onClick={() => setMore(true)}
  55 + icon={<DownloadOutlined />}
  56 + onClick={() => { setMore(true); setIslock(true); }}
59 57 style={{marginLeft: 10}}
60 58 >
61   - 库存批量导出
  59 + 锁件批量导出
62 60 </Button>
63 61 <Button
64 62 type="primary"
65   - icon={<PlusOutlined />}
66   - onClick={() => { setVisible(true); setIsadd(true); }}
67   - style={{ marginLeft: 10}}
  63 + icon={<DownloadOutlined />}
  64 + onClick={() => setMore(true)}
  65 + style={{marginLeft: 10}}
68 66 >
69   - 新增
  67 + 库存批量导出
70 68 </Button>
71 69 </div>
72 70 </div>
... ...
src/pages/pms/storage/partShop/interface.d.ts
... ... @@ -21,7 +21,8 @@ declare namespace PmsStoragePartShop {
21 21 actualStock?: number,
22 22 shopId?: number, // 服务站ID
23 23 shopName?: string // 服务站名称
24   - isOut?: boolean
  24 + isOut?: boolean,
  25 + isLock?:boolean
25 26 }
26 27  
27 28 interface Params {
... ... @@ -77,6 +78,7 @@ declare namespace PmsStoragePartShop {
77 78 isOut?: boolean, // 出入库
78 79 current?: number
79 80 pageSize?:number
  81 + isLock?:boolean // 锁库 ?释放
80 82 }
81 83  
82 84 /**
... ...
src/pages/pms/transfer/HuolalaSetting/api.ts 0 → 100644
  1 +import { http } from '@/typing/http';
  2 +import request from '@/utils/request';
  3 +import { PMS_HOST, HOST } from '@/utils/host';
  4 +
  5 +export interface ListVO{
  6 + /**
  7 + * 财务账户信息id
  8 + */
  9 + id?:number
  10 + /**
  11 + * 往来单位id
  12 + */
  13 + supplierId?:number
  14 + /**
  15 + * 往来单位名称
  16 + */
  17 + supplierName?:string
  18 + /**
  19 + * 签约门店id
  20 + */
  21 + shopId?:number
  22 + /**
  23 + * 签约门店名称
  24 + */
  25 + shopName?:string;
  26 + /**
  27 + * 当前余额
  28 + */
  29 + amount?:number;
  30 + /**
  31 + * 待到账金额
  32 + */
  33 + awaitAmount?:number;
  34 + /**
  35 + * 低余额推待办
  36 + */
  37 + minAmount?:number;
  38 + /**
  39 + * 推待办角色编码
  40 + */
  41 + roleCode?:string;
  42 + /**
  43 + * 推待办角色名称
  44 + */
  45 + roleName?:string;
  46 + /**
  47 + * 发单账号
  48 + */
  49 + account?:string;
  50 + /**
  51 + * 集团id
  52 + */
  53 + groupId?:number;
  54 + /**
  55 + * 创建时间
  56 + */
  57 + time?:string;
  58 +}
  59 +interface Params{
  60 + current?:number,
  61 + pageSize?:number
  62 +}
  63 +export interface saveParams{
  64 + //财务账户信息id
  65 + id?:number;
  66 + /**
  67 + * 往来单位id
  68 + */
  69 + supplierId?:number;
  70 + /**
  71 + * 往来单位名称
  72 + */
  73 + supplierName?:string;
  74 + /**
  75 + * 签约门店id
  76 + */
  77 + shopId?:number;
  78 + /**
  79 + * 低余额推待办
  80 + */
  81 + minAmount?:number;
  82 + /**
  83 + * 推待办角色编码
  84 + */
  85 + roleCode?:string;
  86 + /**
  87 + * 推待办角色名称
  88 + */
  89 + roleName?:string;
  90 + /**
  91 + * 发单账号
  92 + */
  93 + // @NotBlank(message = "发单账号不能为空")
  94 + account?:string;
  95 +}
  96 +interface queryList {
  97 + current?:number
  98 + pageSize?:number
  99 + sysId?:number
  100 +}
  101 +// 查询财务账户信息列表
  102 +export function getList(params: Params):http.PromisePageResp<ListVO> {
  103 + return request.get(`${PMS_HOST}/erp/finance/account/get/page`, {params});
  104 +}
  105 +// 新增/编辑API
  106 +export function saveApi(params: saveParams) {
  107 + return request.post(`${PMS_HOST}/erp/finance/account/exit`, {...params});
  108 +}
  109 +// 推待办角色列表
  110 +export function roleListApi(params: queryList): http.PromisePageResp<Role.Info> {
  111 + return request.get(`${HOST}/role/list`, { params });
  112 +}
  113 +// 删除API
  114 +export function deleteApi(params: {id: number}) {
  115 + return request.post(`${PMS_HOST}/erp/finance/account/delete`, {...params});
  116 +}
0 117 \ No newline at end of file
... ...
src/pages/pms/transfer/HuolalaSetting/components/AddModal.tsx 0 → 100644
  1 +import React, { useEffect, useState } from 'react';
  2 +import {Form, Button, InputNumber, Modal, message, Input } from 'antd';
  3 +import PmsSelect from '@/pages/pms/comonents/PmsSelect';
  4 +import { ListVO, saveApi, roleListApi } from '../api';
  5 +import { getPageListApi, Item as item } from "@/pages/pms/partPlan/PlanSupplier/api";
  6 +import {getShopApi} from '@/pages/pms/storage/partShop/api';
  7 +import usePagination from '@/hooks/usePagination';
  8 +import useInitail from '@/hooks/useInitail';
  9 +
  10 +const Item = Form.Item;
  11 +
  12 +interface Props{
  13 + visible?:boolean,
  14 + onCancel: Function,
  15 + item?:ListVO
  16 +}
  17 +
  18 +export default function Index(props:Props) {
  19 + const { list: suppliers } = usePagination<item>(getPageListApi, { supplierType: 40, pageSize: 500 });
  20 + const { data: shops } = useInitail<PmsStoragePartShop.Option[], {}>(getShopApi, [], {});
  21 + const { list } = usePagination<Role.Info>(roleListApi, { pageSize: 500, sysId: 229 });
  22 + const [loading, setLoading] = useState(false);
  23 + const { visible, onCancel, item } = props;
  24 + const [form] = Form.useForm();
  25 +
  26 + useEffect(() => {
  27 + if (visible && item?.id) {
  28 + form.setFieldsValue({
  29 + supplierId: item.supplierId,
  30 + shopId: item.shopId,
  31 + minAmount: item.minAmount,
  32 + roleCode: item.roleCode,
  33 + account: item.account
  34 + });
  35 + }
  36 + if (!visible) {
  37 + form.resetFields();
  38 + }
  39 + }, [visible]);
  40 +
  41 + const onSave = () => {
  42 + form.validateFields().then(files => {
  43 + const params = {
  44 + id: item?.id,
  45 + supplierId: files.supplierId,
  46 + supplierName: suppliers.find(i => i.supplierId == files.supplierId)?.supplierName,
  47 + shopId: files.shopId,
  48 + minAmount: files.minAmount,
  49 + roleCode: files.roleCode,
  50 + roleName: list.find(i => i.roleCode == files.roleCode)?.roleName,
  51 + account: files.account
  52 + };
  53 + setLoading(true);
  54 + saveApi(params).then(res => {
  55 + message.success("保存成功");
  56 + setLoading(false);
  57 + onCancel();
  58 + }).catch(e => {
  59 + message.error(e.message);
  60 + setLoading(false);
  61 + });
  62 + });
  63 + };
  64 +
  65 + return (
  66 + <Modal
  67 + title={item?.id ? "编辑货拉拉账户配置" : "新增货拉拉账户配置"}
  68 + visible={visible}
  69 + maskClosable={false}
  70 + onCancel={() => onCancel()}
  71 + footer={[
  72 + <Button loading={loading} onClick={() => onCancel()}>取消</Button>,
  73 + <Button loading={loading} type="primary" htmlType="submit" onClick={() => onSave()}>保存</Button>
  74 + ]}
  75 + >
  76 + <Form
  77 + form={form}
  78 + labelCol={{span: 5}}
  79 + wrapperCol={{span: 12}}
  80 + >
  81 + <Item label="往来单位" name="supplierId" rules={[{required: true, message: "请选择往来单位"}]}>
  82 + <PmsSelect
  83 + placeholder="选择往来单位"
  84 + options={suppliers.filter((item, index, self) => {
  85 + return self.findIndex(el => el.supplierId == item.supplierId) === index;
  86 + }).map((item) => ({ value: item.supplierId, label: item.supplierName }))}
  87 + />
  88 + </Item>
  89 + <Item label="签约门店" name="shopId" rules={[{ required: true, message: "请选择签约门店" }]}>
  90 + <PmsSelect
  91 + placeholder="选择签约门店"
  92 + options={shops.map((item: PmsStoragePartShop.Option) => ({ value: item.id, label: item.name }))}
  93 + />
  94 + </Item>
  95 + <Item label="推待办余额" name="minAmount" rules={[{ required: true, message: "请填写金额" }]}>
  96 + <InputNumber style={{width: '100%'}} addonAfter="元" />
  97 + </Item>
  98 + <Item label="推待办角色" name="roleCode" rules={[{ required: true, message: "请选择推办角色" }]}>
  99 + <PmsSelect
  100 + placeholder="选择待办角色"
  101 + options={list.map(item => ({value: item.roleCode, label: item.roleName}))}
  102 + />
  103 + </Item>
  104 + <Item label="发单账号" name="account" rules={[{ required: true, message: "请填写发单账号" }]}>
  105 + <Input />
  106 + </Item>
  107 + </Form>
  108 + </Modal>
  109 + );
  110 +}
... ...
src/pages/pms/transfer/HuolalaSetting/components/ChargeModal.tsx 0 → 100644
  1 +import React from 'react';
  2 +import { Form, Button, InputNumber, Modal } from 'antd';
  3 +import PmsSelect from '@/pages/pms/comonents/PmsSelect';
  4 +
  5 +const Item = Form.Item;
  6 +
  7 +interface Props {
  8 + visible?: boolean,
  9 + onCancel: Function,
  10 + item?: any
  11 +}
  12 +export default function Index(props: Props) {
  13 + const { visible, onCancel, item } = props;
  14 + const [form] = Form.useForm();
  15 +
  16 + const onSave = () => {
  17 + const params = {id: item.id};
  18 + console.log(params);
  19 + };
  20 +
  21 + return (
  22 + <Modal
  23 + title="预付款充值申请"
  24 + visible={visible}
  25 + maskClosable={false}
  26 + onCancel={() => onCancel()}
  27 + footer={[
  28 + <Button onClick={() => onCancel()}>取消</Button>,
  29 + <Button type="primary" htmlType="submit" onClick={() => onSave()}>提交申请</Button>
  30 + ]}
  31 + >
  32 + <Form
  33 + form={form}
  34 + labelCol={{ span: 7 }}
  35 + wrapperCol={{ span: 12 }}
  36 + >
  37 + <Item label="往来单位" name="supplierName" rules={[{ required: true, message: "请选择往来单位" }]}>
  38 + <PmsSelect />
  39 + </Item>
  40 + <Item label="往来单位类型" name="shopName" rules={[{ required: true, message: "请选择签约门店" }]}>
  41 + <PmsSelect />
  42 + </Item>
  43 + <Item label="账户余额" name="amount" rules={[{ required: true, message: "请填写金额" }]}>
  44 + <InputNumber style={{ width: '100%' }} addonAfter="元" disabled />
  45 + </Item>
  46 + <Item label="充值金额" name="awaitAmount" rules={[{ required: true, message: "请填写金额" }]}>
  47 + <InputNumber style={{ width: '100%' }} addonAfter="元" />
  48 + </Item>
  49 + <Item label="账户到账金额" name="awaitAmount" rules={[{ required: true, message: "请填写金额" }]}>
  50 + <InputNumber style={{ width: '100%' }} addonAfter="元" disabled />
  51 + </Item>
  52 + <Item label="结算门店" name="shopName" rules={[{ required: true, message: "请选择推办角色" }]}>
  53 + <PmsSelect />
  54 + </Item>
  55 + <Item label="发票金额要求比例" name="role" rules={[{ required: true, message: "请选择推办角色" }]}>
  56 + <PmsSelect />
  57 + </Item>
  58 + <Item label="结算方式" name="role" rules={[{ required: true, message: "请选择推办角色" }]}>
  59 + <PmsSelect />
  60 + </Item>
  61 + <Item label="附件" name="files">
  62 + <PmsSelect />
  63 + </Item>
  64 + </Form>
  65 + </Modal>
  66 + );
  67 +}
... ...
src/pages/pms/transfer/HuolalaSetting/index.tsx 0 → 100644
  1 +import React, { useState } from 'react';
  2 +import { Card, Button, Table, Divider, Popconfirm, message } from 'antd';
  3 +import { PageHeaderWrapper } from '@ant-design/pro-layout';
  4 +import AddModal from './components/AddModal';
  5 +import ChargeModal from './components/ChargeModal';
  6 +import {getList, ListVO, deleteApi} from './api';
  7 +import usePagination from '@/hooks/usePagination';
  8 +
  9 +const Column = Table.Column;
  10 +export default function Index() {
  11 + const {list, loading, paginationConfig, setParams} = usePagination<ListVO>(getList, [], {});
  12 + const [current, setCurrent] = useState<{ visible: boolean, item: ListVO }>({visible: false, item: {}});
  13 + const [chargeInfo, setChargeInfo] = useState<{ visible: boolean, item: ListVO }>({visible: false, item: {}});
  14 + const data = [{id: 1, supplierName: "货拉拉", shopName: "不过承诺书可能单纯迪士尼才", amount: 3000, minAmount: 1500, roleName: "计划制定员", account: "15725173,16638183"}];
  15 + return (
  16 + <PageHeaderWrapper title="货拉拉账户配置">
  17 + <Card
  18 + extra={<Button type="primary" onClick={() => setCurrent({visible: true, item: {}})}>新增</Button>}
  19 + >
  20 + <Table dataSource={data} rowKey="id" loading={loading} pagination={paginationConfig}>
  21 + <Column title="往来单位" dataIndex="supplierName" />
  22 + <Column title="签约门店" dataIndex="shopName" />
  23 + <Column title="当前余额(元)" dataIndex="amount" />
  24 + <Column title="低余额推待办(元)" dataIndex="minAmount" />
  25 + <Column title="推待办角色" dataIndex="roleName" />
  26 + <Column title="发单账号" dataIndex="account" />
  27 + <Column
  28 + title="操作"
  29 + render={r => (
  30 + <div style={{display: 'flex', flexWrap: 'wrap', alignItems: 'center'}}>
  31 + <a onClick={() => setChargeInfo({visible: true, item: r})}>预付款充值申请</a>
  32 + <Divider type="vertical" />
  33 + <a onClick={() => setCurrent({visible: true, item: r})}>编辑</a>
  34 + <Divider type="vertical" />
  35 + <Popconfirm
  36 + title="确认删除"
  37 + onConfirm={() => {
  38 + deleteApi({id: r.id}).then(res => {
  39 + message.success('操作成功');
  40 + setParams({}, true);
  41 + }).catch(e => message.error(e.message));
  42 + }}
  43 + >
  44 + <a>删除</a>
  45 + </Popconfirm>
  46 + </div>
  47 + )}
  48 + />
  49 + </Table>
  50 + <AddModal visible={current.visible} item={current.item} onCancel={() => setCurrent({ visible: false, item: {} })} />
  51 + <ChargeModal visible={chargeInfo.visible} item={chargeInfo.item} onCancel={() => setChargeInfo({ visible: false, item: {} })} />
  52 + </Card>
  53 + </PageHeaderWrapper>
  54 + );
  55 +}
... ...
src/pages/pms/transfer/transferPool/comonents/Filiter.tsx
... ... @@ -26,9 +26,9 @@ export default function Index() {
26 26 <Input.Search
27 27 allowClear
28 28 enterButton
29   - placeholder="输入关键词进行搜索"
  29 + placeholder="输入关键词搜索"
30 30 onSearch={(value, event) => setParams({keywords: value}, true)}
31   - style={{ width: 220, marginRight: 10 }}
  31 + style={{ width: 200, marginRight: 10, marginBottom: 10 }}
32 32 />
33 33 <PmsSelect
34 34 style={{width: 200, marginRight: 10}}
... ...
src/pages/pms/transfer/transferPool/comonents/PartTable.tsx
... ... @@ -22,7 +22,7 @@ export default function Index() {
22 22 >
23 23 <Column title="配件名称" dataIndex="name" />
24 24 <Column title="配件编码" dataIndex="code" />
25   - <Column title="动态库销比" dataIndex="ratio" />
  25 + <Column title="动态库销比" dataIndex="ratio" render={t => (t ? t.toFixed(2) : '--')} />
26 26 <Column title="调出池配件数量" dataIndex="transferCnt" />
27 27 <Column title="调出库房分析" render={(r:PoolItem) => <a onClick={() => analysis(r, 6)}>查看</a>} />
28 28 <Column title="调入库房分析" render={(r:PoolItem) => <a onClick={() => analysis(r, 7)}>查看</a>} />
... ...
src/pages/pms/transfer/transferPool/comonents/StorageTable.tsx
... ... @@ -23,7 +23,7 @@ export default function Index(props: {out?:boolean}) {
23 23 scroll={{y: 500}}
24 24 >
25 25 <Column title={out ? "调出库房" : "调入库房"} dataIndex="name" />
26   - <Column title="动态库销比" dataIndex="ratio" />
  26 + <Column title="动态库销比" dataIndex="ratio" render={t => (t ? t.toFixed(2) : '--')} />
27 27 <Column title="调出池配件品种" dataIndex="transferKind" />
28 28 <Column title="调出池配件数量" dataIndex="transferCnt" />
29 29 {out ?
... ...
src/pages/pms/transfer/transferPool/comonents/VehicleTable.tsx
... ... @@ -22,7 +22,7 @@ export default function Index() {
22 22 scroll={{y: 500}}
23 23 >
24 24 <Column title="车系" dataIndex="name" />
25   - <Column title="动态库销比" dataIndex="ratio" />
  25 + <Column title="动态库销比" dataIndex="ratio" render={t => (t ? t.toFixed(2) : '--')} />
26 26 <Column title="调出池配件品种" dataIndex="transferKind" />
27 27 <Column title="调出池配件数量" dataIndex="transferCnt" />
28 28 <Column title="调出库房分析" render={(r) => <a onClick={() => analysis(r, 6)}>查看</a>} />
... ...
src/pages/vms/OperationAdministration/components/PlayBackPicker/index.tsx
... ... @@ -59,6 +59,9 @@ function PlayBackPicker(props: any) {
59 59 const { _d: checkDate, _i: nowDate } = date;
60 60 const checkYear = moment(checkDate).format('YYYY-MM-DD');
61 61 const nowYear = moment(nowDate).format('YYYY-MM-DD');
  62 + const checkHours = moment(checkDate).format('HH');
  63 + const nowHours = moment(nowDate).format('HH');
  64 +
62 65 // if (type === 'start') {
63 66 // const hour = moment(date).hour();
64 67 // const minute = moment(date).minute();
... ... @@ -83,24 +86,30 @@ function PlayBackPicker(props: any) {
83 86 // },
84 87 // };
85 88 // }
86   - if (checkYear === nowYear) {
87   - const nowHour = moment(nowDate).hour();
88   - const nowMinute = moment(nowDate).minute();
89   - const nowSecond = moment(nowDate).second();
90   - return {
91   - disabledHours: () => {
92   - const disabledArr = timeArr(24).splice(nowHour, timeArr(24).length - nowHour);
93   - return disabledArr;
94   - },
95   - disabledMinutes: () => {
96   - const disabledArr = timeArr(60).splice(nowMinute, timeArr(60).length - nowMinute);
97   - return disabledArr;
98   - },
99   - disabledSeconds: () => {
100   - const disabledArr = timeArr(60).splice(nowSecond, timeArr(60).length - nowSecond);
101   - return disabledArr;
102   - },
103   - };
  89 +
  90 + const nowHour = moment(nowDate).hour();
  91 + const nowMinute = moment(nowDate).minute();
  92 + const nowSecond = moment(nowDate).second();
  93 + const resultLimit = {
  94 + // type: 'end',
  95 + disabledHours: () => {
  96 + const disabledArr = timeArr(24).splice(nowHour + 1, timeArr(24).length - nowHour);
  97 + return disabledArr;
  98 + },
  99 + disabledMinutes: () => {
  100 + const disabledArr = timeArr(60).splice(nowMinute, timeArr(60).length - nowMinute);
  101 + return disabledArr;
  102 + },
  103 + disabledSeconds: () => {
  104 + const disabledArr = timeArr(60).splice(nowSecond, timeArr(60).length - nowSecond);
  105 + return disabledArr;
  106 + },
  107 + };
  108 + if (checkYear === nowYear && checkHours !== nowHours) {
  109 + return { disabledHours: resultLimit.disabledHours };
  110 + }
  111 + if (checkYear === nowYear && checkHours === nowHours) {
  112 + return resultLimit;
104 113 }
105 114 };
106 115 /**
... ... @@ -135,6 +144,7 @@ function PlayBackPicker(props: any) {
135 144 }}
136 145 disabledDate={disabledDate}
137 146 disabledTime={disabledTracksTime}
  147 + // max={disabledTracksTime}
138 148 onCalendarChange={
139 149 (value: any) => {
140 150 setDateFlag(value);
... ...