Commit 75ceab7cda766cc323aaf19e00fac5eef4084f67

Authored by 曾柯
2 parents e9547bdf 50d3e44c

Merge remote-tracking branch 'origin/master' into quality

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
... ...
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/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
... ...