Browse Source

feat(): 新建运营营销车场折扣页面

tags/PMS_Frontend_v1.0.6-develop
陈宇航 1 year ago
parent
commit
0a2db13a1e
  1. 8
      src/config/character.config.js
  2. 4
      src/pages/MerchantMgm/InvoiceConf/loadable.jsx
  3. 56
      src/pages/OperationCenter/OperationSales/YardDiscount/DebounceSelect.jsx
  4. 291
      src/pages/OperationCenter/OperationSales/YardDiscount/index.scss
  5. 502
      src/pages/OperationCenter/OperationSales/YardDiscount/loadable.jsx
  6. 40
      src/services/OperationCenter/OperationSales/index.js

8
src/config/character.config.js

@ -292,6 +292,14 @@ export default {
{ value: 3, label: "社会类停车场" },
{ value: 4, label: "智慧交通" },
],
// 车场折扣--状态
YardDiscountType: [
{ value: "0", label: "全部" },
{ value: "1", label: "进行中" },
{ value: "2", label: "未开始" },
{ value: "3", label: "已下架" },
{ value: "4", label: "已结束" },
],
PayDevice:[
{
value: '0',

4
src/pages/MerchantMgm/InvoiceConf/loadable.jsx

@ -768,9 +768,9 @@ function InvoiceConf() {
]}
>
<Radio.Group onChange={(e) => {setInvoicePlatform(e.target.value)}}>
<Radio value={1}>航信</Radio>
{/* <Radio value={1}>航信</Radio> */}
<Radio value={2}>航信诺诺</Radio>
<Radio value={3}>百旺</Radio>
{/* <Radio value={3}>百旺</Radio> */}
</Radio.Group>
</Form.Item>
<Form.Item

56
src/pages/OperationCenter/OperationSales/YardDiscount/DebounceSelect.jsx

@ -0,0 +1,56 @@
import { Select, Spin } from 'antd';
import _ from 'lodash';
import React, { useEffect, useMemo, useRef, useState } from 'react';
/**
*
* @param {type} 1车牌号2路段/停车场名称3收费员4活动名称
* @returns
*/
const DebounceSelect = ({
fetchOptions,
ajaxType,
debounceTimeout = 800,
...props
}) => {
const [fetching, setFetching] = useState(false);
const [options, setOptions] = useState([]);
const fetchRef = useRef(0);
const debounceFetcher = useMemo(() => {
const $loadOptions = (value) => {
fetchRef.current += 1;
const fetchId = fetchRef.current;
setOptions([]);
setFetching(true);
fetchOptions({value, type: ajaxType}).then((newOptions) => {
if (fetchId !== fetchRef.current) {
// for fetch callback order
return;
}
setOptions(newOptions);
setFetching(false);
});
};
if(props?.value?.length) {
return _.debounce($loadOptions, 0)
};
return _.debounce($loadOptions, debounceTimeout);
}, [fetchOptions, debounceTimeout]);
useEffect(() => {
if(props?.value?.length) debounceFetcher();
}, []);
return (
<Select
// labelInValue
filterOption={false}
onSearch={debounceFetcher}
showSearch={true}
notFoundContent={fetching ? <Spin size="small" /> : null}
{...props}
options={options}
/>
);
};
export default DebounceSelect;

291
src/pages/OperationCenter/OperationSales/YardDiscount/index.scss

@ -3,3 +3,294 @@ $color-container-bg : var(--color-container-bg);
$color-user-list-bg: var(--color-user-list-bg);
$color-text: var(--color-text);
$color-primary: var(--color-primary);
.yard-discount {
display: flex;
padding-top: 10px;
width: 100%;
height: 100%;
.paid-search {
display: block;
width: 375px;
padding: 10px 10px 20px 20px;
.title {
width: 100%;
font-size: 16px;
font-family:
Microsoft YaHei,
Microsoft YaHei-Bold;
font-weight: 700;
text-align: left;
color: var(--color-text);
margin-bottom: 20px;
}
.form-Wrap {
height: calc(100% - 45px);
overflow-y: auto;
scrollbar-width: none;
-ms-overflow-style: none;
&::-webkit-scrollbar {
display: none;
}
.debounce-select {
.ant-select-selection-overflow-item {
.ant-select-selection-item {
background: transparent;
border: 0;
}
.ant-select-selection-item-remove {
display: none;
}
}
.ant-select-selection-overflow-item-suffix {
// display: none;
}
}
}
.yisa-search {
width: 100%;
display: flex;
align-items: center;
margin-bottom: 24px;
label {
color: var(--color-search-list-item-text);
flex: 0 0 25%;
max-width: 25%;
text-align: right;
padding-right: 8px;
}
.form-con {
flex: 1;
width: 220px;
}
}
.form-btn {
display: flex;
flex-flow: row nowrap;
padding: 0 10px;
justify-content: space-between;
.reset {
width: 90px;
height: 36px;
border-radius: 4px;
}
.submit {
width: calc(100% - 100px);
height: 36px;
border-radius: 4px;
}
}
.ant-select-selector,
.ant-picker,
.ant-input {
background-color: var(--color-search-list-item-bg) !important;
box-shadow: none !important;
color: var(--color-search-list-item-value);
border-color: var(--color-search-list-item-bd) !important;
}
}
.paid-result {
width: calc(100% - 375px);
padding-bottom: 15px;
padding: 20px;
background: var(--color-user-list-bg);
border-top-left-radius: 20px;
box-shadow: 0px 3px 8px 0px rgba(0, 0, 0, 0.08);
.result {
height: 100%;
display: flex;
flex-direction: column;
.row-head {
height: 32px;
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 13px;
}
.result-data {
width: 100%;
height: calc(100% - 45px - 60px);
.table {
width: 100%;
.ant-table-body {
@include scrollBar(var(--color-user-list-bg), #3b97ff);
}
.ant-table-thead {
th {
// padding: 0px 16px;
height: 50px;
}
.ant-table-cell {
background: var(--color-table-header-bg) !important;
font-weight: 700;
&::before {
display: none;
}
}
}
.ant-table-tbody {
tr {
&:nth-child(2n) {
td {
background: #3e4557 !important;
}
}
&:hover {
td {
background: #3e4557 !important;
}
}
td {
background: #3e4557 !important;
// border-bottom-color: #f2f2f2;
}
}
}
.ant-pagination-options {
.ant-select {
&:hover {
.ant-select-selector {
border-color: #f5f6f9;
box-shadow: none;
}
}
}
.ant-select-selector {
border-color: #f5f6f9;
}
.ant-select-focused {
.ant-select-selector {
box-shadow: none !important;
border-color: #f5f6f9 !important;
}
}
.ant-pagination-options-quick-jumper {
input {
background: #3e4557;
border-color: #f5f6f9;
&:focus {
box-shadow: none;
}
}
}
}
.ant-table-cell-fix-left,
.ant-table-cell-fix-right {
z-index: 2;
}
}
}
}
}
}
.yard-discount-sel-modal {
.ant-spin {
margin-left: 50%;
transform: translateX(-50%);
}
}
.start-exception-deal-operate {
.ant-popover-inner-content {
padding: 5px 5px;
width: 100%;
.hover,
.disabled {
padding: 5px 12px;
text-align: center;
}
.hover {
&:hover {
background-color: #414960;
}
}
.disabled {
cursor: no-drop;
color: rgba(255, 255, 255, 0.3);
}
}
}
.yard-discount-modal {
.form-Wrap {
height: calc(100% - 45px);
overflow-y: auto;
scrollbar-width: none;
-ms-overflow-style: none;
&::-webkit-scrollbar {
display: none;
}
.debounce-select {
.ant-select-selection-overflow-item {
.ant-select-selection-item {
background: transparent;
border: 0;
}
.ant-select-selection-item-remove {
display: none;
}
}
.ant-select-selection-overflow-item-suffix {
// display: none;
}
}
}
.yisa-search {
width: 100%;
display: flex;
align-items: center;
margin-bottom: 24px;
label {
color: var(--color-search-list-item-text);
flex: 0 0 25%;
max-width: 20%;
text-align: right;
padding-right: 8px;
}
.form-con {
flex: 1;
width: 220px;
}
em {
color: #a61d24;
}
}
.ant-select-selector,
.ant-picker,
.ant-input {
background-color: var(--color-search-list-item-bg) !important;
box-shadow: none !important;
color: var(--color-search-list-item-value);
border-color: var(--color-search-list-item-bd) !important;
}
.ant-input[disabled] {
color: hsla(0,0%,100%,.3);
}
.ant-select-disabled.ant-select:not(.ant-select-customize-input) .ant-select-selector .ant-select-selection-item {
color: hsla(0,0%,100%,.3);
}
// .ant-modal-footer .ant-btn-default {
// background-color: #636D80;
// &:hover {
// text-decoration: none;
// background: transparent;
// border: 1px solid #636D80;
// }
// }
}

502
src/pages/OperationCenter/OperationSales/YardDiscount/loadable.jsx

@ -1,15 +1,495 @@
import React, { useState, useRef, useEffect } from "react";
// import { message, Pagination, Table, Space, Modal, } from "antd";
// import { dictionary, utils } from "@/config/common";
// import moment from 'moment'
// import { useSessionStorageState, useUpdateEffect, useSize, useUpdate } from 'ahooks';
// import ajax from "@/services"
// import { FormInput, FormSelect, OptionPanel, ResultPanel, FormSliderPicker, AreaCascader, ImgResize, ImgZoom, } from "@/components"
// import "./index.scss";
// import errorImg from "@/assets/images/layout/error.png"
// import { useLocation } from "react-router-dom";
function YardDiscount() {
return <div>YardDiscount</div>
import { message, Pagination, Table, Select, Popconfirm, Input, DatePicker, Button, Popover, Modal } from "antd";
import { dictionary, utils } from "@/config/common";
import moment from "moment";
import { useSessionStorageState } from "ahooks";
import ajax from "@/services";
import { QuickMenu, ParkingRecordModal } from "@/components";
import DebounceSelect from "./DebounceSelect";
import "./index.scss";
import { use } from "echarts";
const { RangePicker } = DatePicker;
const YardDiscount = () => {
//
const defaultData = {
activity: [], //
road: [], //
status: "0", //
pn: 1,
page_size: dictionary?.pageSizeOptions1[0]
};
//
const defaultModal = {
activity: [], //
road: [], //
discount: "", //
start_time: null, //
end_time: null,//
}
//
const tableColumns = [
{
title: "活动名称",
dataIndex: "activity",
key: "activity",
align: "center",
},
{
title: "停车场名称",
dataIndex: "road",
key: "road",
align: "center",
},
{
title: "折扣",
dataIndex: "discount",
key: "discount",
align: "center",
render: (text, record, index) => {
return <>{record.discount || "--"}%</>
},
},
{
title: "活动时间",
dataIndex: "start_time",
key: "start_time",
align: "center",
render: (text, record, index) => {
return <>
<span>{record?.start_time || "--"} {record?.end_time}</span>
</>
},
},
{
title: "状态",
dataIndex: "status",
key: "status",
align: "center",
width: 150,
render: (text, record, index) => {
let content = '--'
switch (text) {
case "0":
content = "全部"
break;
case "1":
content = "进行中"
break;
case "2":
content = "未开始"
break;
case "3":
content = "已下架"
break;
case "4":
content = "已结束"
break;
default:
break;
}
return <>{content}</>
},
},
{
title: "更新时间",
dataIndex: "update_time",
key: "update_time",
align: "center",
},
{
title: '操作',
key: 'operation',
dataIndex: 'operation',
align: "center",
fixed: 'right',
width: 100,
render: (text, record, index) => {
return <>
<Popover
overlayClassName="start-exception-deal-operate"
content={
<div className="operateBtn operate-btn" style={{ cursor: "pointer" }} trigger="hover">
<div
className="hover"
onClick={() => {
setModalData({
activity: record?.activity_id?.split() || [],
road: record?.road_id?.split() || [],
discount: record?.discount || "",
start_time: record?.start_time || null,
end_time: record?.end_time || null
});
setModalVisible({
open: true,
title: "查看",
});
}}
>
查看
</div>
{record?.status == 1 ?
<Popconfirm placement="left" title="您确定要下架该活动吗?" onConfirm={() => { $deleteConfirm(record?.id, "下架") }} okText="确认" cancelText="取消">
<div className="hover">下架</div>
</Popconfirm> :
record?.status == 2 ?
<>
<div
className="hover"
onClick={() => {
setModalData({
activity: record?.activity_id?.split() || [],
road: record?.road_id?.split() || [],
discount: record?.discount || "",
start_time: record?.start_time || null,
end_time: record?.end_time || null
});
setModalVisible({
open: true,
title: "编辑",
});
}}
>
编辑
</div>
<Popconfirm placement="left" title="您确定要删除该活动吗?" onConfirm={() => { $deleteConfirm(record?.id, "删除") }} okText="确认" cancelText="取消">
<div className="hover">删除</div>
</Popconfirm>
</> :
""
}
</div>
}
>
<Button type="primary">操作</Button>
</Popover>
</>
},
},
];
const [formData, setFormData] = useState(defaultData); //
const [sessionData, setSessionData] = useSessionStorageState("yardDiscount", { value: {} }); // session
const [loading, setLoading] = useState(false); //
const [modalVisible, setModalVisible] = useState({open: false, title: ""}); //
const [modalData, setModalData] = useState(defaultModal); //
//
const [resultData, setResultData] = useState({
total: 0,
list: [],
});
//
const $fetchActivityList = (value) => {
return ajax.fetchActivityData({ ...value }).then((res) => {
if (res.status === 20000 || res.status == 0) {
if (res?.data?.length) return res.data;
} else {
message.error(res.message);
}
}).catch((error) => {
message.error(error.message);
});
};
//
const $changePn = (pn, page_size) => {
let temFormData = {};
if (formData.page_size == page_size) {
temFormData = {
...formData,
pn
};
} else {
temFormData = {
...formData,
pn: 1,
page_size,
};
};
setFormData(temFormData);
$getTableList(temFormData);
};
//
const $deleteConfirm = (id, type) => {
let url = type == "下架" ? ajax.yardDiscountDown : ajax.yardDiscountDelete;
url({ id }).then((res) => {
if (res.status === 20000 || res.status == 0) {
message.success(res.message || `${type}成功`);
$getTableList();
} else {
message.error(res.message);
}
}).catch((error) => {
message.error(error.message);
});
};
//
const $getTableList = (value = {}) => {
let _data = {
...formData,
...value,
activity: value?.activity?.length ? value?.activity.join() : formData?.activity?.length ? formData?.activity.join() : "",
road: value?.road?.length ? value?.road.join() : formData?.road?.length ? formData?.road.join() : "",
};
setLoading(true);
ajax.yardDiscountTableData(_data).then((res) => {
setLoading(false);
if (res.status === 20000 || res.status == 0) {
setResultData(res?.data || { total: 0, list: [] });
} else {
message.error(res.message);
}
}).catch((error) => {
message.error(error.message);
});
};
const $disabledDate = (current) => {
// Can not select days before today and today
return current && current <= moment().subtract(1, 'day');
};
useEffect(() => {
let _data = {};
if (sessionData && Object.values(sessionData).length > 0) {
_data = {
activity: sessionData?.activity || [], //
road: sessionData?.road || [], //
pn: 1,
page_size: dictionary?.pageSizeOptions1[0],
};
setFormData({ ..._data });
};
$getTableList(_data);
}, []);
useEffect(() => {
// setSessionData(formData);
}, [formData]);
return (
<div className="yard-discount">
<div className="paid-search">
<div className="title">查询条件</div>
<div className="form-Wrap">
<div className="yisa-search debounce-select">
<label>活动名称</label>
<DebounceSelect
className="form-con"
popupClassName="yard-discount-sel-modal"
placeholder="请输入活动名称"
ajaxType="2"
mode="multiple"
allowClear
value={formData?.activity || []}
fetchOptions={$fetchActivityList}
onChange={(newValue) => {
let value = newValue.slice(-1);
setFormData({
...formData,
activity: value
});
}}
/>
</div>
<div className="yisa-search debounce-select">
<label>停车场名称</label>
<DebounceSelect
className="form-con"
popupClassName="yard-discount-sel-modal"
placeholder="请输入停车场名称"
allowClear
ajaxType="4"
mode="multiple"
value={formData?.road || []}
fetchOptions={$fetchActivityList}
onChange={(newValue) => {
let value = newValue.slice(-1);
setFormData({
...formData,
road: value
});
}}
/>
</div>
<div className="yisa-search">
<label>商户名称</label>
<Select
className="form-con"
placeholder="请选择"
options={dictionary.YardDiscountType}
allowClear
value={formData.status}
onChange={(v) => setFormData({ ...formData, status: v || "0" })}
/>
</div>
<div className="form-btn">
<Button
className="submit"
type="primary"
loading={loading}
onClick={() => {
let _data = {
...formData,
pn: 1,
page_size: dictionary?.pageSizeOptions1[0]
}
setFormData(_data)
$getTableList(_data)
}}
>
查询
</Button>
<Button
className="add"
type="primary"
onClick={() => setModalVisible({open: true, title: "添加"})}
>
添加
</Button>
</div>
</div>
</div>
<div className="paid-result">
<div className="result">
<div className="result-data">
<Table
rowKey={(row) => row.park_id}
className="table"
dataSource={resultData?.list || []}
columns={tableColumns}
pagination={false}
loading={loading}
scroll={{ y: "calc(100vh - 265px)" }}
/>
<Pagination
className="pagination-common"
showSizeChanger={true}
showQuickJumper={true}
showTotal={() => `${resultData.total || 0}`}
total={resultData.total}
current={formData.pn}
pageSize={formData.page_size}
pageSizeOptions={dictionary?.pageSizeOptions1}
onChange={$changePn}
/>
</div>
</div>
</div>
<Modal
className="yard-discount-modal"
title={modalVisible.title}
open={modalVisible.open}
onCancel={() => {
setModalVisible({open: false, title: ""});
setModalData(defaultModal);
}}
destroyOnClose={true}
footer={[
modalVisible.title != "查看" ?
<Button key="提交" type="primary" onClick={() => {console.log(modalData, "这是确定");}}>提交</Button>
: "",
<Button key="取消" onClick={() => {
setModalVisible({open: false, title: ""});
setModalData(defaultModal);
}}>
取消
</Button>,
]}
>
<div className="form-Wrap">
<div className="yisa-search debounce-select">
<label><em>*</em> 活动名称</label>
<DebounceSelect
className="form-con"
popupClassName="yard-discount-sel-modal"
placeholder="请输入活动名称"
disabled={modalVisible.title == "查看" ? true : false}
ajaxType="2"
mode="multiple"
allowClear
value={modalData?.activity || []}
fetchOptions={$fetchActivityList}
onChange={(newValue) => {
let value = newValue.slice(-1);
setModalData({
...modalData,
activity: value
});
}}
/>
</div>
<div className="yisa-search debounce-select">
<label><em>*</em> 停车场名称</label>
<DebounceSelect
className="form-con"
popupClassName="yard-discount-sel-modal"
placeholder="请输入停车场名称"
ajaxType="4"
allowClear
mode="multiple"
disabled={modalVisible.title == "查看" ? true : false}
value={modalData?.road || []}
fetchOptions={$fetchActivityList}
onChange={(newValue) => {
let value = newValue.slice(-1);
setModalData({
...modalData,
road: value
});
}}
/>
</div>
<div className="yisa-search">
<label><em>*</em> 折扣</label>
<Input
className="form-con"
placeholder="请输入折扣"
value={modalData?.discount}
disabled={modalVisible.title == "查看" ? true : false}
suffix="%"
onChange={(e) =>{
let onlyNumber = /^[1-9]\d*$/;
if(onlyNumber.test(e.target.value) || e.target.value.length > 2 ? true : false) {
return message.error("折扣必须填1-99的整数");
}
setFormData({
...modalData,
discount: e.target.value || ""
})
}}
/>
</div>
<div className="yisa-search">
<label><em>*</em> 活动时间</label>
<RangePicker
disabledDate={$disabledDate}
disabled={modalVisible.title == "查看" ? true : false}
value={[
modalData?.start_time ? moment(modalData.start_time) : null,
modalData?.end_time ? moment(modalData.end_time) : null,
]}
onChange={(date, time) => {
setModalData({
...modalData,
start_time: time[0],
end_time: time[1]
})
}}
/>
</div>
</div>
</Modal>
</div>
);
}
export default YardDiscount;

40
src/services/OperationCenter/OperationSales/index.js

@ -98,6 +98,42 @@ const handleDiscountOperate = (p) => {
data: p,
});
};
// 车场折扣-活动名称及停车场名称
const fetchActivityData = (p) => {
return ajax({
url: "/api/bpm/record/info",
type: "post",
data: p,
});
};
// 车场折扣--表格数据
const yardDiscountTableData = (p) => {
return ajax({
url: "/api/ope/parkdiscount/list",
type: "post",
data: p,
});
};
// 车场折扣--下架
const yardDiscountDown = (p) => {
return ajax({
url: "/api/ope/parkdiscount/down",
type: "post",
data: p,
});
};
// 车场折扣--删除
const yardDiscountDelete = (p) => {
return ajax({
url: "/api/ope/parkdiscount/delete",
type: "post",
data: p,
});
};
// 优惠券管理-优惠券规则编辑
const handleCouponRulesEdit = (p) => {
return ajax({
@ -193,4 +229,8 @@ export default {
handleOffExport,
handleCouponDelete,
getCountList,
fetchActivityData,
yardDiscountTableData,
yardDiscountDown,
yardDiscountDelete,
};
Loading…
Cancel
Save