fix(staff)

This commit is contained in:
wang_yp 2025-03-24 18:13:33 +08:00
parent 6fecf2b553
commit a2f288073e
27 changed files with 926 additions and 213 deletions

View File

@ -9,7 +9,7 @@
<meta name="description" content="Web site created using create-react-app" />
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<title>黄水武装</title>
<title>农浓深情</title>
</head>
<body>

View File

@ -2,22 +2,7 @@ import Modal from "antd/lib/modal";
import { PlusOutlined } from "@ant-design/icons";
import Upload, { RcFile, UploadFile, UploadProps } from "antd/lib/upload";
import { useEffect, useState } from "react";
import Config from "@/util/config";
interface UploadFileProps {
imgList: Array<UploadFileEx>;
onChnage: Function;
maxCount?: number;
}
interface UploadFileEx extends UploadFile {
systemImageId?: number;
bannerName?: string;
file_name?: string;
file_url?: string;
redictUrl?: string;
id?: number;
}
import { UploadFileProps } from "./form/interface";
const getBase64 = (file: RcFile): Promise<string> =>
new Promise((resolve, reject) => {
@ -45,16 +30,17 @@ const AliUpload = (props: UploadFileProps) => {
};
useEffect(() => {
setFileList(props.imgList);
}, [props.imgList]);
setFileList(props.value ?? []);
}, [props.value]);
const handleChange: UploadProps["onChange"] = ({ fileList: newFileList }) => {
newFileList.forEach((i) => {
i.url = `${Config.baseUrl}/uploads/` + i.name;
i.fileName = i.name;
if (i.status === "done") {
i.url = i.response.data.record.url;
i.fileName = i.response.data.record.file_name;
}
});
setFileList(newFileList);
props.onChnage(newFileList);
props.onChange!(newFileList);
};
const uploadButton = (
<div>
@ -64,16 +50,17 @@ const AliUpload = (props: UploadFileProps) => {
);
return (
<div style={{ margin: 10 }}>
<div style={{ margin: 10 }} id={props.id}>
<Upload
{...props}
listType="picture-card"
fileList={files}
action={`${Config.baseUrl}/v1/public/fts/upload`}
action={`/v1/public/fts/upload`}
onPreview={handlePreview}
maxCount={props.maxCount ?? 4}
onChange={handleChange}
>
{files.length >= (props.maxCount??4) ? null : uploadButton}
{files.length >= (props.maxCount ?? 4) ? null : uploadButton}
</Upload>
<Modal
open={previewOpen}

View File

@ -1,4 +1,4 @@
import { FormInstance } from "antd"
import { FormInstance, UploadFile } from "antd"
import React from "react"
export enum FormType {
input = "input",
@ -23,10 +23,12 @@ export interface FormDatas {
name: string,
value: any,
selectUrl?: string,
key?: string,
selectList?: Array<selectItem>
checkboxData?: Array<any>,
radioData?: Array<any>,
rules: Array<rules>
rules: Array<rules>,
selectModel?: "multiple" | "tags" | undefined,
}
export interface SimpleFormData {
@ -55,3 +57,19 @@ export interface selectItem {
name: string,
id: number,
}
export interface UploadFileProps {
value?: Array<UploadFileEx>;
onChange?: (value: Array<UploadFileEx>) => void;
maxCount?: number;
id?: string;
}
export interface UploadFileEx extends UploadFile {
systemImageId?: number;
bannerName?: string;
file_name?: string;
file_url?: string;
redictUrl?: string;
id?: number;
}

View File

@ -3,24 +3,24 @@ import { FormDatas } from "./interface";
import { useEffect, useState } from "react";
import { base } from "@/service/base";
const { Option } = Select;
export const FormSelect = (v: FormDatas) => {
export const FormSelect = (props: FormDatas) => {
const [list, setList] = useState<any>([]);
useEffect(() => {
if (v.selectList && v.selectList.length > 0) {
setList(v.selectList);
if (props.selectList && props.selectList.length > 0) {
setList(props.selectList);
} else {
base.get(`${v.selectUrl}/?size=50&offset=1`, "").then((res) => {
base.get(`${props.selectUrl}`, {size:50,offset:1}).then((res) => {
setList(res.data.record ?? []);
});
}
}, [v.selectUrl, v.selectList]);
}, [props.selectUrl, props.selectList]);
return (
<Form.Item key={v.label} label={v.label} name={v.name} rules={v.rules}>
<Select placeholder="">
<Form.Item key={props.label} label={props.label} name={props.name} rules={props.rules}>
<Select placeholder="" mode={props.selectModel}>
{list?.map((v: any) => {
return (
<Option key={v.id} value={v.id}>
{v.name}
<Option key={v.identity} value={v.identity}>
{v[props.key ?? "name"]}
</Option>
);
})}

View File

@ -101,23 +101,11 @@ const SimpleForm = (props: SimpleFormData) => {
<Form.Item
key={v.label}
label={v.label}
valuePropName="fileList"
name={v.name}
rules={v.rules}
initialValue={v.value}
getValueFromEvent={(e) => {
if (Array.isArray(e)) {
return e;
}
return e && e.fileList;
}}
>
<AliUpload
imgList={form.getFieldValue(v.name) ?? []}
onChnage={(res) => {
form.setFieldValue(v.name, res);
}}
/>
<AliUpload />
</Form.Item>
);
case FormType.textarea:

View File

@ -31,13 +31,14 @@ const LayOut = (props: Store) => {
alignItems: "center",
justifyContent: "space-between",
};
const logoStyle = { width: 60, color: "white" };
const logoStyle = { width: 140, color: "white",display:"flex" };
const contentstyle = {
padding: 12,
margin: 0,
minHeight: 280,
background: colorBgContainer,
borderRadius: borderRadiusLG,
};
const breadItem = [
{ title: "首页" },
@ -55,7 +56,8 @@ const LayOut = (props: Store) => {
<Layout>
<Header style={headStyle}>
<div style={logoStyle}>
{/* <Image src={logo} /> */}
<Image src={logo} style={{ width: 40, height: 40,marginRight:10 ,borderRadius:10 }} />
<span></span>
</div>
<Dropdown menu={{ items }}>
<Avatar icon={<UserOutlined />} />
@ -83,7 +85,7 @@ const LayOut = (props: Store) => {
</Sider>
<Layout style={{ padding: "0 15px 15px" }}>
<Breadcrumb items={breadItem} style={{ margin: "10px 0" }} />
<Content style={contentstyle}>
<Content style={{...contentstyle,overflowX:"auto"}}>
<Outlet />
</Content>
<Footer style={{ textAlign: "center" }}>

View File

@ -23,7 +23,12 @@ export const items: ItemType<MenuItemType>[] = [
key: "/city",
label: `城市管理`,
icon: <UserOutlined />,
children: [{ key: "/city/list", label: `城市管理` }],
children: [
{ key: "/city/list", label: `城市管理` },
{ key: "/city/hum", label: `人文管理` },
{ key: "/city/history", label: `历史底蕴` },
{ key: "/city/food", label: `地方美食` },
],
},
{
key: "/sku",

View File

@ -0,0 +1,69 @@
import { FormType } from "@/components/form/interface";
import { UserDataType } from "@/model/userModel";
import { CityConfig } from "@/service/config";
import { ColumnsType } from "antd/lib/table";
import { Image } from "antd";
export const formConfig = [
{
type: FormType.input,
label: "标题",
name: "title",
value: "",
rules: [{ required: true, message: "城市名称不能为空!" }],
},
{
type: FormType.input,
label: "副标题",
name: "sub_title",
value: "",
rules: [{ required: true, message: "城市编码不能为空" }],
},
{
type: FormType.upload,
label: "缩略图",
name: "cover",
value: [],
maxCount: 1,
rules: [{ required: true, message: "缩略图不能为空" }],
},
{
type: FormType.select,
label: "城市",
name: "city_identity",
value: "",
key: "city_name",
selectUrl: CityConfig.LIST,
rules: [{ required: true, message: "城市不能为空" }],
},
{
type: FormType.editor,
label: "内容",
name: "content",
value: "",
rules: [{ required: true, message: "城市不能为空" }],
},
];
export const columns: ColumnsType<UserDataType> = [
{
title: "美食名称",
dataIndex: "title",
fixed: "left",
},
{
title: "美食副标题",
dataIndex: "sub_title",
},
{
title: "首图",
dataIndex: "cover",
render: (text, record) => {
return <Image width={50} src={text} />;
},
},
{
title: "城市",
dataIndex: "city_identity",
},
];

View File

@ -0,0 +1,79 @@
import React from "react";
import { Button, Space, Modal, FormInstance } from "antd";
import { Store } from "antd/lib/form/interface";
import { inject, observer } from "mobx-react";
import { useEffect, useState } from "react";
import BTable from "@/components/b_table";
import SimpleForm from "@/components/form/simple_form";
import { columns, formConfig } from "./config";
const Food = (props: Store) => {
const { cityLocalStore } = props;
const [isModalOpen, setIsModalOpen] = useState<boolean>(false);
const formRef = React.useRef<FormInstance>(null);
const [userId, setId] = useState<Number | null>(null);
const [record, setRecord] = useState<any>(null);
// 获取列表数据
useEffect(() => {
cityLocalStore.getlist();
}, [cityLocalStore]);
return (
<div className="contentBox">
<Space direction="vertical" size="middle" style={{ display: "flex" }}>
<Button type="default" onClick={() => setIsModalOpen(true)}>
</Button>
<BTable
store={cityLocalStore}
scroll={{ x: "max-content" }}
columns={columns}
dataSource={cityLocalStore.list}
deleteCallback={(record) => {
cityLocalStore.deleteItem(record);
}}
editCallback={(record) => {
setIsModalOpen(true);
let data = {...record}
data.cover = [{url:record.cover}]
formRef.current?.setFieldsValue(data);
setRecord(data);
setId(data.id);
}}
/>
<Modal
title={!userId ? "添加" : "编辑"}
width="80%"
open={isModalOpen}
afterClose={() => formRef.current?.resetFields()}
onOk={() => formRef.current?.submit()}
okText="确定"
cancelText="取消"
onCancel={() => {
setId(null);
setRecord(null);
setIsModalOpen(false);
}}
>
<SimpleForm
formName={"city_form"}
formRef={formRef}
colProps={25}
onFinish={() => {
let data = formRef.current?.getFieldsValue()
data.cover = data.cover[0].url
cityLocalStore.add(data)
setIsModalOpen(false);
}}
createCallback={() => {
formRef.current?.setFieldsValue(record);
}}
formDatas={formConfig as any}
></SimpleForm>
</Modal>
</Space>
</div>
);
};
export default inject("cityLocalStore")(observer(Food));

View File

@ -0,0 +1,69 @@
import { FormType } from "@/components/form/interface";
import { UserDataType } from "@/model/userModel";
import { CityConfig } from "@/service/config";
import { ColumnsType } from "antd/lib/table";
import { Image } from "antd";
export const formConfig = [
{
type: FormType.input,
label: "标题",
name: "title",
value: "",
rules: [{ required: true, message: "城市名称不能为空!" }],
},
{
type: FormType.input,
label: "副标题",
name: "sub_title",
value: "",
rules: [{ required: true, message: "城市编码不能为空" }],
},
{
type: FormType.upload,
label: "缩略图",
name: "cover",
value: [],
maxCount: 1,
rules: [{ required: true, message: "缩略图不能为空" }],
},
{
type: FormType.select,
label: "城市",
name: "city_identity",
value: "",
key: "city_name",
selectUrl: CityConfig.LIST,
rules: [{ required: true, message: "城市不能为空" }],
},
{
type: FormType.editor,
label: "内容",
name: "content",
value: "",
rules: [{ required: true, message: "城市不能为空" }],
},
];
export const columns: ColumnsType<UserDataType> = [
{
title: "标题",
dataIndex: "title",
fixed: "left",
},
{
title: "副标题",
dataIndex: "sub_title",
},
{
title: "首图",
dataIndex: "cover",
render: (text, record) => {
return <Image width={50} src={text} />;
},
},
{
title: "城市",
dataIndex: "city_identity",
},
];

View File

@ -0,0 +1,78 @@
import React from "react";
import { Button, Space, Modal, FormInstance } from "antd";
import { Store } from "antd/lib/form/interface";
import { inject, observer } from "mobx-react";
import { useEffect, useState } from "react";
import BTable from "@/components/b_table";
import SimpleForm from "@/components/form/simple_form";
import { columns, formConfig } from "./config";
const History = (props: Store) => {
const { cityhisStore } = props;
const [isModalOpen, setIsModalOpen] = useState<boolean>(false);
const formRef = React.useRef<FormInstance>(null);
const [userId, setId] = useState<Number | null>(null);
const [record, setRecord] = useState<any>(null);
// 获取列表数据
useEffect(() => {
cityhisStore.getlist();
}, [cityhisStore]);
return (
<div className="contentBox">
<Space direction="vertical" size="middle" style={{ display: "flex" }}>
<Button type="default" onClick={() => setIsModalOpen(true)}>
</Button>
<BTable
store={cityhisStore}
scroll={{ x: "max-content" }}
columns={columns}
dataSource={cityhisStore.list}
deleteCallback={(record) => {
cityhisStore.deleteItem(record);
}}
editCallback={(record) => {
let data = {...record}
data.cover = [{url:record.cover}]
formRef.current?.setFieldsValue(data);
setRecord(record);
setId(record.id);
}}
/>
<Modal
title={!userId ? "添加" : "编辑"}
width={800}
open={isModalOpen}
afterClose={() => formRef.current?.resetFields()}
onOk={() => formRef.current?.submit()}
okText="确定"
cancelText="取消"
onCancel={() => {
setId(null);
setRecord(null);
setIsModalOpen(false);
}}
>
<SimpleForm
formName={"city_form"}
formRef={formRef}
colProps={25}
onFinish={() => {
let data = formRef.current?.getFieldsValue();
data.cover = data.cover[0].url;
cityhisStore.add(data);
setIsModalOpen(false);
}}
createCallback={() => {
formRef.current?.setFieldsValue(record);
}}
formDatas={formConfig as any}
></SimpleForm>
</Modal>
</Space>
</div>
);
};
export default inject("cityhisStore")(observer(History));

View File

@ -0,0 +1,69 @@
import { FormType } from "@/components/form/interface";
import { UserDataType } from "@/model/userModel";
import { CityConfig } from "@/service/config";
import { ColumnsType } from "antd/lib/table";
import { Image } from "antd";
export const formConfig = [
{
type: FormType.input,
label: "标题",
name: "title",
value: "",
rules: [{ required: true, message: "城市名称不能为空!" }],
},
{
type: FormType.input,
label: "副标题",
name: "sub_title",
value: "",
rules: [{ required: true, message: "城市编码不能为空" }],
},
{
type: FormType.upload,
label: "缩略图",
name: "cover",
value: [],
maxCount: 1,
rules: [{ required: true, message: "缩略图不能为空" }],
},
{
type: FormType.select,
label: "城市",
name: "city_identity",
value: "",
key: "city_name",
selectUrl: CityConfig.LIST,
rules: [{ required: true, message: "城市不能为空" }],
},
{
type: FormType.editor,
label: "内容",
name: "content",
value: "",
rules: [{ required: true, message: "城市不能为空" }],
},
];
export const columns: ColumnsType<UserDataType> = [
{
title: "标题",
dataIndex: "title",
fixed: "left",
},
{
title: "副标题",
dataIndex: "sub_title",
},
{
title: "首图",
dataIndex: "cover",
render: (text, record) => {
return <Image width={50} src={text} />;
},
},
{
title: "城市",
dataIndex: "city_identity",
},
];

View File

@ -0,0 +1,79 @@
import React from "react";
import { Button, Space, Modal, FormInstance } from "antd";
import { Store } from "antd/lib/form/interface";
import { inject, observer } from "mobx-react";
import { useEffect, useState } from "react";
import BTable from "@/components/b_table";
import SimpleForm from "@/components/form/simple_form";
import { columns, formConfig } from "./config";
const HumIntro = (props: Store) => {
const { cityhumStore } = props;
const [isModalOpen, setIsModalOpen] = useState<boolean>(false);
const formRef = React.useRef<FormInstance>(null);
const [userId, setId] = useState<Number | null>(null);
const [record, setRecord] = useState<any>(null);
// 获取列表数据
useEffect(() => {
cityhumStore.getlist();
}, [cityhumStore]);
return (
<div className="contentBox">
<Space direction="vertical" size="middle" style={{ display: "flex" }}>
<Button type="default" onClick={() => setIsModalOpen(true)}>
</Button>
<BTable
store={cityhumStore}
scroll={{ x: "max-content" }}
columns={columns}
dataSource={cityhumStore.list}
deleteCallback={(record) => {
cityhumStore.deleteItem(record);
}}
editCallback={(record) => {
setIsModalOpen(true);
let data = {...record}
data.cover = [{url:record.cover}]
formRef.current?.setFieldsValue(data);
setRecord(record);
setId(record.id);
}}
/>
<Modal
title={!userId ? "添加" : "编辑"}
width={800}
open={isModalOpen}
afterClose={() => formRef.current?.resetFields()}
onOk={() => formRef.current?.submit()}
okText="确定"
cancelText="取消"
onCancel={() => {
setId(null);
setRecord(null);
setIsModalOpen(false);
}}
>
<SimpleForm
formName={"city_form"}
formRef={formRef}
colProps={25}
onFinish={() => {
let data = formRef.current?.getFieldsValue();
data.cover = data.cover[0].url;
cityhumStore.add(data);
setIsModalOpen(false);
}}
createCallback={() => {
formRef.current?.setFieldsValue(record);
}}
formDatas={formConfig as any}
></SimpleForm>
</Modal>
</Space>
</div>
);
};
export default inject("cityhumStore")(observer(HumIntro));

View File

@ -1,76 +1,11 @@
import React from "react";
import { Button, Space, Modal, FormInstance } from "antd";
import { Store } from "antd/lib/form/interface";
import { inject, observer } from "mobx-react";
import { useEffect, useState } from "react";
import { columns, formConfig } from "./config";
import BTable from "@/components/b_table";
import SimpleForm from "@/components/form/simple_form";
const City = (props: Store) => {
const { cityStore } = props;
const [isModalOpen, setIsModalOpen] = useState<boolean>(false);
const formRef = React.useRef<FormInstance>(null);
const [userId, setId] = useState<Number | null>(null);
const [record, setRecord] = useState<any>(null);
// 获取列表数据
useEffect(() => {
cityStore.getlist();
}, [cityStore]);
import { Outlet } from "react-router";
const City = () => {
return (
<div className="contentBox">
<Space direction="vertical" size="middle" style={{ display: "flex" }}>
<Button type="default" onClick={() => setIsModalOpen(true)}>
</Button>
<BTable
store={cityStore}
scroll={{ x: "max-content" }}
columns={columns}
dataSource={cityStore.list}
deleteCallback={(record) => {
cityStore.deleteItem(record);
}}
editCallback={(record) => {
setIsModalOpen(true);
formRef.current?.setFieldsValue(record);
setRecord(record);
setId(record.id);
}}
/>
<Modal
title={!userId ? "添加" : "编辑"}
width={800}
open={isModalOpen}
afterClose={() => formRef.current?.resetFields()}
onOk={() => formRef.current?.submit()}
okText="确定"
cancelText="取消"
onCancel={() => {
setId(null);
setRecord(null);
setIsModalOpen(false);
}}
>
<SimpleForm
formName={"city_form"}
formRef={formRef}
colProps={25}
onFinish={() => {
cityStore.add(formRef.current?.getFieldsValue())
setIsModalOpen(false);
}}
createCallback={() => {
formRef.current?.setFieldsValue(record);
}}
formDatas={formConfig as any}
></SimpleForm>
</Modal>
</Space>
<div>
<Outlet />
</div>
);
};
export default inject("cityStore")(observer(City));
export default City;

75
src/pages/city/list.tsx Normal file
View File

@ -0,0 +1,75 @@
import React from "react";
import { Button, Space, Modal, FormInstance } from "antd";
import { Store } from "antd/lib/form/interface";
import { inject, observer } from "mobx-react";
import { useEffect, useState } from "react";
import { columns, formConfig } from "./config";
import BTable from "@/components/b_table";
import SimpleForm from "@/components/form/simple_form";
const City = (props: Store) => {
const { cityStore } = props;
const [isModalOpen, setIsModalOpen] = useState<boolean>(false);
const formRef = React.useRef<FormInstance>(null);
const [userId, setId] = useState<Number | null>(null);
const [record, setRecord] = useState<any>(null);
// 获取列表数据
useEffect(() => {
cityStore.getlist();
}, [cityStore]);
return (
<div className="contentBox">
<Space direction="vertical" size="middle" style={{ display: "flex" }}>
<Button type="default" onClick={() => setIsModalOpen(true)}>
</Button>
<BTable
store={cityStore}
scroll={{ x: "max-content" }}
columns={columns}
dataSource={cityStore.list}
deleteCallback={(record) => {
cityStore.deleteItem(record);
}}
editCallback={(record) => {
setIsModalOpen(true);
formRef.current?.setFieldsValue(record);
setRecord(record);
setId(record.id);
}}
/>
<Modal
title={!userId ? "添加" : "编辑"}
width={800}
open={isModalOpen}
afterClose={() => formRef.current?.resetFields()}
onOk={() => formRef.current?.submit()}
okText="确定"
cancelText="取消"
onCancel={() => {
setId(null);
setRecord(null);
setIsModalOpen(false);
}}
>
<SimpleForm
formName={"city_form"}
formRef={formRef}
colProps={25}
onFinish={() => {
cityStore.add(formRef.current?.getFieldsValue())
setIsModalOpen(false);
}}
createCallback={() => {
formRef.current?.setFieldsValue(record);
}}
formDatas={formConfig as any}
></SimpleForm>
</Modal>
</Space>
</div>
);
};
export default inject("cityStore")(observer(City));

View File

@ -1,29 +1,6 @@
import { FormType } from "@/components/form/interface";
import { UserDataType } from "@/model/userModel";
import { ColumnsType } from "antd/lib/table";
export const formConfig = [
{
type: FormType.input,
label: "商品名称",
name: "tag_name",
value: "",
rules: [{ required: true, message: "标签名称不能为空!" }],
},
{
type: FormType.input,
label: "标签描述",
name: "tag_desc",
value: "",
rules: [{ required: true, message: "城市编码不能为空" }],
},
{
type: FormType.input,
label: "标签排序",
name: "tag_sort",
value: "1",
rules: [{ required: true, message: "标签排序不能为空" }],
},
];
import { Image } from "antd";
export const columns: ColumnsType<UserDataType> = [
{
@ -31,13 +8,12 @@ export const columns: ColumnsType<UserDataType> = [
dataIndex: "sku_name",
fixed: "left",
},
{
title: "库存",
dataIndex: "sku_stock",
},
{
title: "商品分类",
dataIndex: "sku_cat_identity",
dataIndex: "sku_cat",
render: (text, record) => {
return <span>{text.name}</span>;
},
},
{
title: "品牌",
@ -46,6 +22,9 @@ export const columns: ColumnsType<UserDataType> = [
{
title: "缩略图",
dataIndex: "sku_thumb",
render: (text, record) => {
return <Image width={50} src={text} />;
},
},
{
title: "商品介绍",
@ -53,6 +32,9 @@ export const columns: ColumnsType<UserDataType> = [
},
{
title: "所属城市",
dataIndex: "city_identity",
dataIndex: "city",
render: (text, record) => {
return <span>{text.city_name}</span>;
},
},
];

View File

@ -1,17 +1,15 @@
import React from "react";
import { Button, Space, Modal, FormInstance } from "antd";
import { Button, Space } from "antd";
import { Store } from "antd/lib/form/interface";
import { inject, observer } from "mobx-react";
import { useEffect, useState } from "react";
import { columns, formConfig } from "./config";
import { useEffect } from "react";
import { columns } from "./config";
import BTable from "@/components/b_table";
import SimpleForm from "@/components/form/simple_form";
import { useNavigate } from "react-router";
const Sku = (props: Store) => {
const { skuStore } = props;
const [isModalOpen, setIsModalOpen] = useState<boolean>(false);
const formRef = React.useRef<FormInstance>(null);
const [userId, setId] = useState<Number | null>(null);
const [record, setRecord] = useState<any>(null);
const nav = useNavigate();
// 获取列表数据
useEffect(() => {
@ -21,7 +19,7 @@ const Sku = (props: Store) => {
return (
<div className="contentBox">
<Space direction="vertical" size="middle" style={{ display: "flex" }}>
<Button type="default" onClick={() => setIsModalOpen(true)}>
<Button type="default" onClick={() => nav("/sku/add")}>
</Button>
<BTable
@ -33,41 +31,9 @@ const Sku = (props: Store) => {
skuStore.deleteItem(record);
}}
editCallback={(record) => {
setIsModalOpen(true);
formRef.current?.setFieldsValue(record);
setRecord(record);
setId(record.id);
}}
/>
<Modal
title={!userId ? "添加" : "编辑"}
width={800}
open={isModalOpen}
afterClose={() => formRef.current?.resetFields()}
onOk={() => formRef.current?.submit()}
okText="确定"
cancelText="取消"
onCancel={() => {
setId(null);
setRecord(null);
setIsModalOpen(false);
}}
>
<SimpleForm
formName={"tag_form"}
formRef={formRef}
colProps={25}
onFinish={() => {
skuStore.add(formRef.current?.getFieldsValue())
setIsModalOpen(false);
}}
createCallback={() => {
formRef.current?.setFieldsValue(record);
}}
formDatas={formConfig as any}
></SimpleForm>
</Modal>
</Space>
</div>
);

View File

@ -0,0 +1,147 @@
import SimpleForm from "@/components/form/simple_form";
import { Button, Form, FormInstance, InputNumber, Select, Space } from "antd";
import React, { useEffect } from "react";
import { formConfig } from "./sku_add_config";
import { inject, observer } from "mobx-react";
import { MinusCircleOutlined } from "@ant-design/icons";
import { Store } from "antd/es/form/interface";
const { Option } = Select;
const SkuAdd = (props: Store) => {
const formRef = React.useRef<FormInstance>(null);
const { skuStore } = props;
useEffect(() => {
skuStore.getSkuSpecCat();
});
const create = () => {
let data = formRef.current?.getFieldsValue();
let obj = {...data}
let files:any = []
obj.sku_thumb = data.sku_thumb[0].url;
if (data.files && data.files.length > 0) {
data.files.forEach((v)=>{
if(v.url){
files.push({
file_name:v.fileName,
file_url:v.url,
file_type:1,
})
}
})
}
obj.files = files
skuStore.add(obj);
};
return (
<div style={{ margin: "0 auto", overflowX: "auto", height: "80%" }}>
<div
style={{
padding: "10px",
marginLeft: 18,
marginBottom: 10,
fontSize: "1.2rem",
display: "flex",
justifyContent: "space-between",
}}
>
<span></span>
<Button onClick={() => formRef.current?.submit()}></Button>
</div>
<SimpleForm
formName={"tag_form"}
formRef={formRef}
colProps={20}
span={2}
childrenPosi={true}
onFinish={() => create()}
createCallback={() => {
// formRef.current?.setFieldsValue(record);
}}
formDatas={formConfig as any}
>
<Form.List name="sku_price" initialValue={[{}]}>
{(fields, { add, remove }) => {
return (
<>
{fields.map(({ key, name }) => (
<Space
key={key}
style={{
display: "flex",
border: "1px solid #f3f3f3",
padding: "10px",
margin: "10px",
alignItems: "center",
}}
>
<Form.Item
label="规格"
style={{ margin: "0px" }}
labelCol={{ span: 10, offset: 0 }}
name={[name, "sku_spec_id"]}
rules={[{ required: true, message: "规格" }]}
>
<Select placeholder="" style={{ width: "100px" }}>
{skuStore.skuSpec?.map((v: any) => {
return (
<Option key={v.identity} value={v.identity}>
{v.spec_name}
</Option>
);
})}
</Select>
</Form.Item>
<Form.Item
label="零售价"
style={{ margin: "0px" }}
labelCol={{ span: 12, offset: 0 }}
name={[name, "sku_price"]}
rules={[{ required: true, message: "零售价" }]}
>
<InputNumber placeholder="零售价" />
</Form.Item>
<Form.Item
label="优惠价"
name={[name, "sku_sale_price"]}
style={{ margin: "0px" }}
labelCol={{ span: 12, offset: 0 }}
rules={[{ required: true, message: "优惠价" }]}
>
<InputNumber placeholder="优惠价" />
</Form.Item>
<Form.Item
name={[name, "sku_stock"]}
style={{ margin: "0px" }}
labelCol={{ span: 12, offset: 0 }}
label="库存"
rules={[{ required: true, message: "库存" }]}
>
<InputNumber placeholder="库存" />
</Form.Item>
<MinusCircleOutlined
onClick={() => remove(name)}
style={{ marginLeft: "20px" }}
/>
</Space>
))}
<Form.Item style={{ marginTop: "10px" }}>
<Button
type="dashed"
onClick={() => {
add();
}}
>
</Button>
</Form.Item>
</>
);
}}
</Form.List>
</SimpleForm>
</div>
);
};
export default inject("skuStore")(observer(SkuAdd));

View File

@ -0,0 +1,62 @@
import { FormType } from "@/components/form/interface";
import { CityConfig, SkuCatConfig, TagConfig } from "@/service/config";
export const formConfig = [
{
type: FormType.input,
label: "商品名称",
name: "sku_name",
value: "",
rules: [{ required: true, message: "商品名称不能为空!" }],
},
{
type: FormType.select,
label: "标签",
name: "tags_id",
value: "",
key: "tag_name",
selectModel: "tags",
selectUrl: TagConfig.LIST,
rules: [{ required: true, message: "不能为空" }],
},
{
type: FormType.select,
label: "分类",
name: "sku_cat_identity",
value: "1",
selectUrl: SkuCatConfig.LIST,
rules: [{ required: true, message: "分类不能为空" }],
},
{
type: FormType.upload,
label: "缩略图",
name: "sku_thumb",
value: [],
maxCount: 1,
rules: [{ required: true, message: "缩略图不能为空" }],
},
{
type: FormType.select,
label: "城市",
name: "city_identity",
value: "",
key: "city_name",
selectUrl: CityConfig.LIST,
rules: [{ required: true, message: "城市不能为空" }],
},
{
type: FormType.upload,
label: "附件图",
name: "files",
value: [],
maxCount: 10,
rules: [{ required: true, message: "附件图不能为空" }],
},
{
type: FormType.textarea,
label: "描述",
name: "sku_desc",
rules: [{ required: true, message: "描述不能为空" }],
},
];

View File

@ -3,6 +3,7 @@ import LayOut from "@/components/layout/layout";
import { rbac } from "./routers/rbac_router";
import { sku } from "./routers/sku_router";
import { sys } from "./routers/sys_router";
import { city } from "./routers/city_router";
const routers = createHashRouter([
{
@ -26,6 +27,7 @@ const routers = createHashRouter([
...rbac,
...sku,
...sys,
...city,
{
path: "/order/list",
index: true,
@ -33,13 +35,7 @@ const routers = createHashRouter([
Component:(await import("@/pages/order")).default,
})
},
{
path: "/city/list",
index: true,
lazy: async() => ({
Component:(await import("@/pages/city")).default,
})
},
],
},
{

View File

@ -0,0 +1,38 @@
export const city = [
{
path: "/city",
lazy: async () => ({
Component: (await import("@/pages/city")).default,
}),
children: [
{
path: "/city/list",
index: true,
lazy: async () => ({
Component: (await import("@/pages/city/list")).default,
}),
},
{
path: "/city/history",
index: true,
lazy: async () => ({
Component: (await import("@/pages/city/history")).default,
}),
},
{
path: "/city/hum",
index: true,
lazy: async () => ({
Component: (await import("@/pages/city/hum_intro")).default,
}),
},
{
path: "/city/food",
index: true,
lazy: async () => ({
Component: (await import("@/pages/city/food")).default,
}),
},
],
},
];

View File

@ -12,6 +12,13 @@ export const sku = [
Component: (await import("@/pages/sku/sku")).default,
}),
},
{
path: "/sku/add",
index: true,
lazy: async () => ({
Component: (await import("@/pages/sku/sku/sku_add")).default,
}),
},
{
path: "/sku/cat",
index: true,

View File

@ -14,6 +14,26 @@ class CityConfig {
static DELETE: string = "/city";
}
class CityLocalFoodConfig {
static ADD: string = "/cityFood";
static EDIT: string = "/cityFood";
static LIST: string = "/cityFood/list";
static DELETE: string = "/cityFood";
}
class CityHistoryConfig {
static ADD: string = "/cityHistory";
static EDIT: string = "/cityHistory";
static LIST: string = "/cityHistory/list";
static DELETE: string = "/cityHistory";
}
class CityHumIntroConfig {
static ADD: string = "/cityHumIntro";
static EDIT: string = "/cityHumIntro";
static LIST: string = "/cityHumIntro/list";
static DELETE: string = "/cityHumIntro";
}
class SkuConfig {
static ADD: string = "/sku";
@ -49,4 +69,4 @@ class SpecConfig {
static LIST: string = "/skuSpec/list";
static DELETE: string = "/skuSpec";
}
export { UserConfig, CityConfig, SkuCatConfig, SkuConfig, Orderconfig, TagConfig, SpecConfig };
export { UserConfig, CityConfig, SkuCatConfig, SkuConfig, Orderconfig, TagConfig, SpecConfig, CityHistoryConfig, CityHumIntroConfig, CityLocalFoodConfig };

View File

@ -1,7 +1,7 @@
import { makeObservable } from "mobx";
import BaseStore from "./baseStore";
import { UserDataType } from "@/model/userModel";
import { CityConfig } from "@/service/config";
import { CityConfig, CityHistoryConfig, CityHumIntroConfig, CityLocalFoodConfig } from "@/service/config";
class CityStore extends BaseStore<UserDataType> {
constructor() {
@ -10,4 +10,28 @@ class CityStore extends BaseStore<UserDataType> {
}
}
const cityStore = new CityStore();
export default cityStore;
class CityHisStore extends BaseStore<UserDataType> {
constructor() {
super(CityHistoryConfig)
makeObservable(this, {})
}
}
const cityhisStore = new CityHisStore();
class CityHumStore extends BaseStore<UserDataType> {
constructor() {
super(CityHumIntroConfig)
makeObservable(this, {})
}
}
const cityhumStore = new CityHumStore();
class CityLocalStore extends BaseStore<UserDataType> {
constructor() {
super(CityLocalFoodConfig)
makeObservable(this, {})
}
}
const cityLocalStore = new CityLocalStore();
export { cityStore, cityLocalStore, cityhisStore, cityhumStore };

View File

@ -1,5 +1,5 @@
import usrStore from '@/store/user'
import cityStore from '@/store/city'
import { cityStore, cityLocalStore, cityhisStore, cityhumStore } from '@/store/city'
import orderStore from './order';
import tagStore from './tag';
import skuStore from './sku';
@ -13,7 +13,10 @@ const store = {
tagStore,
skuStore,
skuCatStore,
skuSpecStore
skuSpecStore,
cityLocalStore,
cityhisStore,
cityhumStore
};
export default store;

View File

@ -1,13 +1,28 @@
import { makeObservable } from "mobx";
import { action, makeObservable, observable } from "mobx";
import BaseStore from "./baseStore";
import { UserDataType } from "@/model/userModel";
import { SkuConfig } from "@/service/config";
import { SkuConfig, SpecConfig } from "@/service/config";
import { base } from "@/service/base";
import { message } from "antd";
class SkuStore extends BaseStore<UserDataType> {
skuSpec = []
constructor() {
super(SkuConfig)
makeObservable(this, {})
makeObservable(this, {
skuSpec: observable,
getSkuSpecCat: action,
})
}
// 获取规格
async getSkuSpecCat() {
let data = await base.get(SpecConfig.LIST, { size: 30, offset: 1 })
if (data.code !== 200) {
message.error(data.msg)
return false
}
this.skuSpec = data.data.record
};
}
const skuStore = new SkuStore();
export default skuStore;

View File

@ -1,5 +1,5 @@
class Config {
static baseUrl = "/v1";
// static baseUrl = "http://127.0.0.1:12215/v1";
static baseUrl1 = "http://127.0.0.1:12215/v1";
}
export default Config;