This commit is contained in:
PC-202306242200\Administrator
2024-09-20 10:33:40 +08:00
parent 2081393a33
commit 0744635890
32 changed files with 1271 additions and 33 deletions

View File

@@ -0,0 +1,87 @@
/*
* @Note:
* @Author: 2058827620@qq.com
* @Date: 2022-04-03 17:02:15
*/
import { ProForm, ModalForm, ProFormSelect, ProFormText, ProFormCaptcha } from '@ant-design/pro-components';
import { Tree } from 'antd';
import { useEffect, useRef } from 'react';
import FilesManager from '@/components/FilesManage/index';
// import services from '@/services/admin';
// const { smsSendcode } = services.SmsController;
// const { shopLevelItems } = services.ShopLevelController;
// const { shopItems } = services.ShopController;
export default ({ values, modalOpenState, onModalOpenState, onSubmit }) => {
const restFormRef = useRef();
useEffect(() => {
restFormRef.current?.setFieldsValue(values);
}, [values]);
return (
<>
<ModalForm
title="活动-作废"
formRef={restFormRef}
submitter={{
searchConfig: {
resetText: '重置',
},
resetButtonProps: {
onClick: () => {
restFormRef.current?.resetFields();
},
},
}}
initialValues={values}
onFinish={onSubmit}
open={modalOpenState}
onOpenChange={onModalOpenState}
>
<ProFormText hidden={true} width="md" name="id" />
<ProForm.Group>
<ProFormText
rules={[{ required: true, message: '请输入' }]}
width="md"
name="username"
label="用户名"
placeholder="请输入"
/>
</ProForm.Group>
<ProForm.Group>
<ProFormText
rules={[{ required: true, message: '请输入' }]}
width="md"
name="mobile"
label="手机号"
placeholder="请输入"
/>
</ProForm.Group>
<ProForm.Group>
<ProFormCaptcha
placeholder={'请输入验证码'}
captchaTextRender={(timing, count) => {
if (timing) {
return `${count} ${'获取验证码'}`;
}
return '获取验证码';
}}
label="验证码"
name="code"
rules={[
{
required: true,
message: '请输入验证码!',
},
]}
onGetCaptcha={async () => {
const { data } = await smsSendcode();
}}
/>
</ProForm.Group>
</ModalForm>
</>
);
};

View File

@@ -0,0 +1,132 @@
/*
* @Note:
* @Author: 2058827620@qq.com
* @Date: 2022-04-03 17:02:15
*/
import { ProForm, ModalForm, ProFormSelect, ProFormText, ProFormDatePicker, ProFormRadio } from '@ant-design/pro-components';
import { Tree } from 'antd';
import { useEffect, useRef, useState } from 'react';
import FilesManager from '@/components/FilesManage/index';
// import services from '@/services/admin';
// const { shopLevelItems } = services.ShopLevelController;
// const { shopItems } = services.ShopController;
export default ({ values, modalOpenState, onModalOpenState, onSubmit }) => {
const restFormRef = useRef();
const [shopOption, setShopOption] = useState([]);
const searchShop = (e) => {
console.log(e);
}
useEffect(() => {
restFormRef.current?.setFieldsValue(values);
}, [values]);
const handleFinish = async (formValues) => {
await onSubmit(formValues);
restFormRef.current?.resetFields();
};
return (
<>
<ModalForm
title="513活动-添加"
formRef={restFormRef}
submitter={{
searchConfig: {
resetText: '重置',
},
resetButtonProps: {
onClick: () => {
restFormRef.current?.resetFields();
},
},
}}
initialValues={values}
onFinish={handleFinish}
open={modalOpenState}
onOpenChange={onModalOpenState}
>
<ProForm.Group>
<ProFormText
width="md"
name="username"
label="用户名"
placeholder="请输入用户名"
rules={[{ required: true, message: '请输入' }]}
/>
<ProFormText
width="md"
name="mobile"
label="手机号"
placeholder="请输入手机号"
rules={[{ required: true, message: '请输入手机号' },{ pattern: /^1[3-9]\d{9}$/, message: '请输入有效的手机号' }]}
/>
<ProFormRadio.Group
label="时间"
name="m"
initialValue="6月"
rules={[{ required: true, message: '请选择' }]}
options={[
{ label: '6月', value: '6月' },
{ label: '12月', value: '12月' },
{ label: '24月', value: '24月' },
{ label: '36月', value: '36月' },
{ label: '48月', value: '48月' },
{ label: '60月', value: '60月' },
]}
/>
<ProFormText
width="md"
name={['info', 'car_name']}
label="车辆型号"
placeholder="请输入车辆型号"
/>
<ProFormText
width="md"
name={['info', 'realname']}
label="车主姓名"
placeholder="请输入车主姓名"
/>
<ProFormText
width="md"
name={['info', 'plate_code']}
label="车牌号码"
placeholder="请输入车牌号码"
/>
<ProFormText
width="md"
name={['info', 'car_code']}
label="车架号码"
placeholder="请输入车架号码"
/>
<ProFormText
width="md"
name={['info', 'bank_num']}
label="还款卡号"
placeholder="请输入还款卡号"
/>
<ProFormText
width="md"
name={['info', 'bank_name']}
label="银行名称"
placeholder="请输入银行名称"
/>
<ProFormText
width="md"
name={['info', 'todate']}
label="还款日期"
placeholder="请输入还款日期"
/>
</ProForm.Group>
</ModalForm>
</>
);
};

View File

@@ -0,0 +1,245 @@
import React, { useRef, useEffect, useState } from 'react';
import { history } from '@umijs/max';
import CreateFormModal from './components/CreateFormModal';
import CancellationModal from './components/CancellationModal';
import { Select, Space, Image, Button } from 'antd';
import {
PageContainer,
ProTable,
} from '@ant-design/pro-components';
import dayjs from 'dayjs';
import { exportLink } from '@/utils/func';
import AuthConsumer from '@/components/Authority';
// import services from '@/services/admin';
// const { shopActivityItems, shopDeleteItems } = services.ShopActivityController;
// const { shopItems } = services.ShopController;
// const { shopActivity } = services.ShopActivity;
export default () => {
const [createFormModal, setCreateFormModal] = useState(false);
const [cancellationModal, setCancellationModal] = useState(false)
const initRow = {
shop_id: '',
todate: '',
};
const initRowCancellationModal = {
username: "",
mobile: "",
code: ""
}
const [row, setRow] = useState(initRow);
const [rowCancellationModal, setRowCancellationModal] = useState(initRowCancellationModal);
const actionRef = useRef();
const [config, setConfig] = useState();
const [shopOption, setShopOption] = useState([]);
const [searchParams, setSearchParams] = useState(null);
const searchShop = (value) => {
shopItems({
username: value
}).then(({ data }) => {
const arr = [];
data?.data?.map((item) => {
item.label = `${item.username} ${item.mobile}`;
arr.push(item);
});
setShopOption(arr);
});
}
const handleCreate = async (fields) => {
setRow(fields);
// let data = JSON.parse(JSON.stringify(fields))
// const { m, mobile, username, ...rest } = data;
// const extracted = { m, mobile, username };
// const remainingData = { ...rest };
const { success } = await shopActivity(fields);
if (success) {
setRow(initRow);
actionRef.current?.reload();
setCreateFormModal(false);
}
};
const handleCreateFormModal = async (fields) => {
setRowCancellationModal(fields)
const { success } = await shopDeleteItems(fields);
if (success) {
setRowCancellationModal(initRow);
actionRef.current?.reload();
setCancellationModal(false);
}
}
const columns = [
{
title: '活动名称',
dataIndex: 'title',
search: false,
},
{
title: '投资人',
dataIndex: 'shop_id',
render: (_, record) => {
return <>
<div>{record?.shop?.username}</div>
<div>{record?.shop?.mobile}</div>
<div>{record?.vip}</div>
</>
},
renderFormItem: (
_,
{ type, defaultRender, formItemProps, fieldProps, ...rest },
form,
) => {
return <Select
{...fieldProps}
allowClear
showSearch
placeholder="请输入用户名"
style={{ width: "100%" }}
filterOption={false}
onSearch={
(e) => {
if (!e) {
return;
}
searchShop(e);
}
}
fieldNames={{
label: "label",
value: "id"
}}
options={shopOption}
/>
},
},
{
title: '时间',
dataIndex: 'm',
search: false,
render: (_, record) => {
return record?.m + '个月'
},
},
{
title: '有效期',
dataIndex: 'type',
search: false,
render: (_, record) => {
return record?.valid_time ? dayjs(record?.valid_time * 1000).format('YYYY-MM-DD') : ''
},
},
{
title: '客户资料',
dataIndex: 'type',
search: false,
render: (_, record) => {
return <>
<div>{record?.info?.car_name}</div>
<div>{record?.info?.realname}</div>
<div>{record?.info?.plate_code}</div>
<div>{record?.info?.car_code}</div>
<div>{record?.info?.bank_num}</div>
<div>{record?.info?.bank_name}</div>
<div>{record?.info?.todate}</div>
</>
},
},
{
title: '创建时间',
dataIndex: 'created_at',
search: false,
}
];
return (
<PageContainer
ghost
>
<>
<CreateFormModal
values={row}
modalOpenState={createFormModal}
onModalOpenState={setCreateFormModal}
onSubmit={handleCreate}
/>
<CancellationModal
values={rowCancellationModal}
modalOpenState={cancellationModal}
onModalOpenState={setCancellationModal}
onSubmit={handleCreateFormModal}
/>
<ProTable
actionRef={actionRef}
rowKey="id"
search={{
defaultCollapsed: false,
}}
toolBarRender={() => [
<AuthConsumer action={'admin/shop_activity/create'} key="admin/shop_activity/create">
<Button
type="primary"
style={{ background: '#67c23a' }}
onClick={() => {
setCreateFormModal(true)
}}
>
</Button>
</AuthConsumer>,
<AuthConsumer action={'admin/shop_activity/export'} key="admin/shop_activity/export">
<Button type="primary" onClick={() => {
window.location.href = exportLink(searchParams, '/admin/shop_activity/export');
}}></Button>
</AuthConsumer>,
<AuthConsumer action={'admin/shop_activity/delete'} key="admin/shop_activity/delete">
<Button
danger
type="primary"
onClick={() => {
setCancellationModal(true)
}}
>
</Button>
</AuthConsumer>
]}
request={async (params, sorter, filter) => {
setSearchParams({ token: '', ...params });
const { data, success } = await shopActivityItems({
...params,
sorter,
filter,
});
return {
data: data?.items || [],
total: data?.total,
success,
};
}}
columns={columns}
/>
</>
</PageContainer>
);
};

View File

@@ -0,0 +1,171 @@
import React, { useRef, useEffect, useState } from 'react';
import { Select, Space, Image, Button } from 'antd';
import {
PageContainer,
ProTable,
} from '@ant-design/pro-components';
export default () => {
const initRow = {
shop_id: '',
todate: '',
};
const initRowCancellationModal = {
username: "",
mobile: "",
code: ""
}
const [row, setRow] = useState(initRow);
const [rowCancellationModal, setRowCancellationModal] = useState(initRowCancellationModal);
const actionRef = useRef();
const [shopOption, setShopOption] = useState([]);
const [searchParams, setSearchParams] = useState(null);
const searchShop = (value) => {
shopItems({
username: value
}).then(({ data }) => {
const arr = [];
data?.data?.map((item) => {
item.label = `${item.username} ${item.mobile}`;
arr.push(item);
});
setShopOption(arr);
});
}
const columns = [
{
title: '活动名称',
dataIndex: 'title',
search: false,
},
{
title: '投资人',
dataIndex: 'shop_id',
render: (_, record) => {
return <>
<div>用户名{record?.shop?.username}</div>
<div>手机号{record?.shop?.mobile}</div>
</>
},
renderFormItem: (
_,
{ type, defaultRender, formItemProps, fieldProps, ...rest },
form,
) => {
return <Select
{...fieldProps}
allowClear
showSearch
placeholder="请输入用户名"
style={{ width: "100%" }}
filterOption={false}
onSearch={
(e) => {
if (!e) {
return;
}
searchShop(e);
}
}
fieldNames={{
label: "label",
value: "id"
}}
options={shopOption}
/>
},
},
{
title: '认领时间',
dataIndex: 'todate',
search: false,
},
{
title: '充电桩',
dataIndex: 'device',
search: false,
render: (_, record) => {
let ids = record?.device.map((item) => {
return item.id
})
return ids.join(',')
},
},
{
title: '创建时间',
dataIndex: 'created_at',
search: false,
}
];
return (
<PageContainer
ghost
>
<>
<ProTable
actionRef={actionRef}
rowKey="id"
search={{
defaultCollapsed: false,
}}
toolBarRender={() => [
// <AuthConsumer action={'admin/shop_activity/create'} key="admin/shop_activity/create">
// <Button
// type="primary"
// style={{ background: '#67c23a' }}
// onClick={() => {
// setCreateFormModal(true)
// }}
// >
// 添加
// </Button>
// </AuthConsumer>,
// <AuthConsumer action={'admin/shop_activity/export'} key="admin/shop_activity/export">
// <Button type="primary" onClick={() => {
// window.location.href = exportLink(searchParams, '/admin/shop_activity/export');
// }}>导出表格</Button>
// </AuthConsumer>,
// <AuthConsumer action={'admin/shop_activity/delete'} key="admin/shop_activity/delete">
// <Button
// danger
// type="primary"
// onClick={() => {
// setCancellationModal(true)
// }}
// >
// 作废
// </Button>
// </AuthConsumer>
]}
request={async (params, sorter, filter) => {
setSearchParams({ token: '', ...params });
const { data, success } = await shopActivityItems813({
...params,
sorter,
filter,
});
return {
data: data?.items || [],
total: data?.total,
success,
};
}}
columns={columns}
/>
</>
</PageContainer>
);
};

View File

@@ -0,0 +1,147 @@
import React, { useEffect, useState } from 'react';
import { contentcategoryPage } from '@/services/note/cate';
import {
ProForm,
ProFormDigit,
ProFormText,
ProFormDateTimePicker
} from '@ant-design/pro-components';
import { Form, Modal, InputNumber } from 'antd';
import { useIntl } from '@umijs/max';
import FilesManager from '@/components/FilesManage/index';
import { ContentUtils } from 'braft-utils'
// 引入编辑器组件
import BraftEditor from 'braft-editor'
// 引入编辑器样式
import 'braft-editor/dist/index.css'
const RoleForm: React.FC = (props: any) => {
const [editorState, setEditorState] = useState(BraftEditor.createEditorState(''))
const [form] = Form.useForm();
const { values } = props;
useEffect(() => {
setEditorState(BraftEditor.createEditorState(values.detail))
form.resetFields();
form.setFieldsValue(values);
}, [form, props]);
const intl = useIntl();
const handleOk = () => {
form.submit();
};
const handleCancel = () => {
props.onCancel();
};
const handleFinish = async (values: any) => {
values.detail = editorState.toHTML()
props.onSubmit(values);
};
const controls = [
'undo', 'redo', 'separator',
'font-size', 'line-height', 'letter-spacing', 'separator',
'text-color', 'bold', 'italic', 'underline', 'strike-through', 'separator',
'superscript', 'subscript', 'remove-styles', 'emoji', 'separator', 'text-indent', 'text-align', 'separator',
'headings', 'list-ul', 'list-ol', 'blockquote', 'code', 'separator',
'link', 'separator', 'hr', 'separator',
'clear'
]
const onChange = async (e) => {
const videoExtensions = ['.mp4', '.mkv', '.avi', '.mov', '.wmv', '.flv', '.webm', '.m4v', '.3gp', '.3g2'];
// 将URL转换为小写以便进行不区分大小写的比较
const lowerCaseUrl = e.toLowerCase();
// 检查链接是否以任何一个视频扩展名结尾
if (videoExtensions.some(e => lowerCaseUrl.endsWith(e))) {
setEditorState(ContentUtils.insertMedias(editorState, [{
type: 'VIDEO',
url: e
}]));
} else {
setEditorState(ContentUtils.insertMedias(editorState, [{ type: 'IMAGE', url: e, },]))
}
}
const extendControls = [
'separator',
{
key: 'FilesManagerImage', // 控件唯一标识,必传
title: '上传图片/视频', // 指定鼠标悬停提示文案
html: null, // 指定在按钮中渲染的html字符串
text: <FilesManager
fileType="images"
mode=""
imagesShow={false}
onChange={onChange}
count={1}
/>, // 指定按钮文字此处可传入jsx若已指定html则text不会显示
onClick: () => {
console.log('Hello World!');
},
}
]
return (
<Modal
width={800}
title={'公告管理'}
open={props.open}
forceRender
destroyOnClose
onOk={handleOk}
onCancel={handleCancel}
>
<ProForm
form={form}
submitter={false}
layout="horizontal"
onFinish={handleFinish}>
<ProFormDigit
name="id"
label={'ID'}
disabled
hidden={true}
/>
<ProForm.Group>
<ProFormText
name="title"
label={'标题'}
placeholder="请输入标题"
/>
</ProForm.Group>
<ProForm.Group>
<ProFormDateTimePicker
rules={[{ required: true, message: '请选择' }]}
name="startTime"
label="开始日期"
/>
<ProFormDateTimePicker
rules={[{ required: true, message: '请选择' }]}
name="endTime"
label="结束日期"
/>
</ProForm.Group>
<ProForm.Group>
<ProForm.Item
name="detail"
>
<div className="border-solid border-2 border-indigo-600">
<BraftEditor value={editorState} controls={controls} extendControls={extendControls} onChange={(val) => {
setEditorState(val)
}} />
</div>
</ProForm.Item>
</ProForm.Group>
</ProForm>
</Modal>
);
};
export default RoleForm;

View File

@@ -0,0 +1,227 @@
import { activityPage,deleteBatchByIds,activityAdd,activityUpdate } from '@/services/activity/index';
import React, { useState, useRef, useEffect } from 'react';
import { useIntl, FormattedMessage, useAccess } from '@umijs/max';
import { Button, message, Modal, Image } from 'antd';
import { ActionType, FooterToolbar, PageContainer, ProColumns, ProTable } from '@ant-design/pro-components';
import { PlusOutlined, DeleteOutlined, ExclamationCircleOutlined } from '@ant-design/icons';
import UpdateForm from './edit';
import { DataNode } from 'antd/es/tree';
/**
* 添加节点
*
* @param fields
*/
const handleAdd = async (fields) => {
const hide = message.loading('正在添加');
try {
fields.status = fields.status ? 0 : 1
await activityAdd({ ...fields });
hide();
message.success('添加成功');
return true;
} catch (error) {
hide();
return false;
}
};
/**
* 更新节点
*
* @param fields
*/
const handleUpdate = async (fields: API.System.Menu) => {
const hide = message.loading('正在修改');
try {
await activityUpdate(fields);
hide();
message.success('修改成功');
return true;
} catch (error) {
hide();
return false;
}
};
const handleRemoveOne = async (selectedRow: API.System.Menu) => {
const hide = message.loading('正在删除');
if (!selectedRow) return true;
try {
const params = [selectedRow.id];
await deleteBatchByIds(params);
hide();
message.success('删除成功');
return true;
} catch (error) {
hide();
message.error('删除失败,请重试');
return false;
}
};
const MenuTableList: React.FC = () => {
const [modalVisible, setModalVisible] = useState<boolean>(false);
const intRow = {
"id": 1,
"imageUrl": "",
"sortOrder": 0,
"status": 0,
"title": "",
"jumpUrl": ""
}
const actionRef = useRef<ActionType>();
const [currentRow, setCurrentRow] = useState(intRow);
const access = useAccess();
/** 国际化配置 */
const intl = useIntl();
useEffect(() => {
}, []);
const columns = [
{
title: 'ID',
dataIndex: 'id',
valueType: 'text',
search: false,
},
{
title: '标题',
dataIndex: 'title',
valueType: 'text',
search: true,
},
{
title: '开始时间',
dataIndex: 'startTime',
valueType: 'text',
search: false,
},
{
title: '结束时间',
dataIndex: 'endTime',
valueType: 'text',
search: false,
},
{
title: '创建时间',
dataIndex: 'createTime',
valueType: 'text',
search: false,
},
{
title: '操作',
dataIndex: 'option',
width: '220px',
valueType: 'option',
render: (_, record) => [
<Button
type="link"
size="small"
hidden={!access.hasPerms('admin/banner/update')}
onClick={() => {
setModalVisible(true);
setCurrentRow(record);
}}
>
</Button>,
<Button
type="link"
size="small"
danger
// hidden={!access.hasPerms('admin:banner:update')}
onClick={async () => {
Modal.confirm({
title: '删除',
content: '确定删除该项吗?',
okText: '确认',
cancelText: '取消',
onOk: async () => {
const success = await handleRemoveOne(record);
if (success) {
if (actionRef.current) {
actionRef.current.reload();
}
}
},
});
}}
>
</Button>,
],
},
];
return (
<PageContainer>
<div style={{ width: '100%', float: 'right' }}>
<ProTable<API.System.Menu>
actionRef={actionRef}
rowKey="id"
key="menuList"
search={{
labelWidth: 120,
}}
toolBarRender={() => [
<Button
type="primary"
key="add"
onClick={async () => {
setCurrentRow(undefined);
setModalVisible(true);
}}
>
<PlusOutlined />
</Button>
]}
request={async (params, sorter, filter) => {
let { data } = await activityPage(params)
return {
data: data?.records || [],
total: data?.total,
};
}}
columns={columns}
/>
</div>
<UpdateForm
onSubmit={async (values) => {
let success = false;
if (values.id) {
success = await handleUpdate({ ...values });
} else {
success = await handleAdd({ ...values });
}
if (success) {
setModalVisible(false);
setCurrentRow(undefined);
if (actionRef.current) {
actionRef.current.reload();
}
}
}}
onCancel={() => {
setModalVisible(false);
setCurrentRow(undefined);
}}
open={modalVisible}
values={currentRow || {}}
/>
</PageContainer>
);
};
export default MenuTableList;

View File

@@ -4,6 +4,9 @@ import { PageContainer, ProTable } from '@ant-design/pro-components';
import { Card, Col, Row, Statistic, Divider, Tag, Image } from 'antd';
import { ArrowDownOutlined, ArrowUpOutlined } from '@ant-design/icons';
import { statMallStatistics, getAmountAndGoodsCount } from '@/services/home/index'
import { Line } from '@ant-design/charts';
export default () => {
const [deviceData, setDeviceData] = useState([]);
const [profit, setProfit] = useState([]);
@@ -12,10 +15,12 @@ export default () => {
data: deviceData,
xField: 'name',
yField: 'value',
seriesField: 'category',
seriesField: 'type',
xAxis: {
type: 'time',
},
padding: 'auto',
legend: { position: 'right-top' },
yAxis: {
label: {
// 数值格式化为千分位
@@ -25,7 +30,29 @@ export default () => {
};
useEffect(() => {
statMallStatistics().then((res) => {
setProfit(res.data)
})
getAmountAndGoodsCount().then((res) => {
let list = []
res.data.map((item, index) => {
list.push({
"name": item.createTime,
"category": "商品数量",
"value": item.goodsCount,
"type": 1
})
list.push({
"name": item.createTime,
"category": "金额",
"value": item.amountCount,
"type": 2
})
})
setDeviceData(list)
})
}, []);
return (
@@ -79,7 +106,7 @@ export default () => {
<Card>
<Statistic
title="今天成交"
value={profit?.shop_count?.today}
value={profit?.todayTransaction}
precision={2}
prefix="¥"
/>
@@ -89,7 +116,7 @@ export default () => {
<Card>
<Statistic
title="昨天成交"
value={profit?.shop_count?.yesterday}
value={profit?.yesterdayTransaction}
precision={2}
prefix="¥"
/>
@@ -99,7 +126,7 @@ export default () => {
<Card>
<Statistic
title="上周成交"
value={profit?.shop_count?.week}
value={profit?.lastWeekTransaction}
precision={2}
prefix="¥"
/>
@@ -109,14 +136,15 @@ export default () => {
<Card>
<Statistic
title="上月成交"
value={profit?.shop_count?.month}
value={profit?.lastMonthTransaction}
precision={2}
prefix="¥"
/>
</Card>
</Col>
</Row>
{/* <Divider>商城(商品数量/金额)-折线图</Divider> */}
<Divider>(/)-线</Divider>
<Line {...deviceConfig} />
</>
);
};