add animation

This commit is contained in:
wang_yp 2025-03-16 00:02:24 +08:00
parent af787ba1af
commit 6f37a95953
33 changed files with 387 additions and 516 deletions

View File

@ -122,7 +122,7 @@ module.exports = function (webpackEnv) {
options: cssOptions,
},
{
loader:'less-loader',
loader: 'less-loader',
// loader: require.resolve('less-loader')
options: {
lessOptions: {
@ -320,7 +320,7 @@ module.exports = function (webpackEnv) {
.map(ext => `.${ext}`)
.filter(ext => useTypeScript || !ext.includes('ts')),
alias: {
'@':path.join(__dirname,'../src/'),
'@': path.join(__dirname, '../src/'),
// Support React Native Web
// https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
'react-native': 'react-native-web',
@ -783,5 +783,13 @@ module.exports = function (webpackEnv) {
// Turn off performance processing because we utilize
// our own hints via the FileSizeReporter
performance: false,
devServer: {
proxy: [
{
context: ['/api'],
target: 'http://127.0.0.1:12215',
},
],
}
};
};

16
package-lock.json generated
View File

@ -1,11 +1,11 @@
{
"name": "ball_admin",
"name": "store",
"version": "0.1.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "ball_admin",
"name": "store",
"version": "0.1.0",
"dependencies": {
"@amap/amap-jsapi-loader": "^1.0.1",
@ -7637,9 +7637,9 @@
}
},
"node_modules/caniuse-lite": {
"version": "1.0.30001660",
"resolved": "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001660.tgz",
"integrity": "sha512-GacvNTTuATm26qC74pt+ad1fW15mlQ/zuTzzY1ZoIzECTP8HURDfF43kNxPgf7H1jmelCBQTTbBNxdSXOA7Bqg==",
"version": "1.0.30001704",
"resolved": "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001704.tgz",
"integrity": "sha512-+L2IgBbV6gXB4ETf0keSvLr7JUrRVbIaB/lrQ1+z8mRcQiisG5k+lG6O4n6Y5q6f5EuNfaYXKgymucphlEXQew==",
"funding": [
{
"type": "opencollective",
@ -39394,9 +39394,9 @@
}
},
"caniuse-lite": {
"version": "1.0.30001660",
"resolved": "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001660.tgz",
"integrity": "sha512-GacvNTTuATm26qC74pt+ad1fW15mlQ/zuTzzY1ZoIzECTP8HURDfF43kNxPgf7H1jmelCBQTTbBNxdSXOA7Bqg=="
"version": "1.0.30001704",
"resolved": "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001704.tgz",
"integrity": "sha512-+L2IgBbV6gXB4ETf0keSvLr7JUrRVbIaB/lrQ1+z8mRcQiisG5k+lG6O4n6Y5q6f5EuNfaYXKgymucphlEXQew=="
},
"canvg": {
"version": "3.0.10",

View File

@ -94,6 +94,7 @@
"build": "node scripts/build.js",
"test": "node scripts/test.js"
},
"proxy": "http://127.0.0.1:12215/",
"eslintConfig": {
"extends": [
"react-app",

View File

@ -1,59 +0,0 @@
.modal {
width: 100%;
height: 100%;
position: fixed;
left: 0;
top: 0;
text-align: center;
z-index: 9999;
background: rgba(0, 0, 0, .45);
display: flex;
align-items: center;
justify-content: center;
animation-name: mode_animation;
animation-duration: .2s;
.modal-content {
min-width: 600px;
min-height: 300px;
background-color: white;
border-radius: 10px;
padding: 10px;
display: flex;
flex-direction: column;
.modal-header {
display: flex;
align-items: flex-end;
justify-content: flex-end;
.close-btn{
font-size: 20px;
font-weight: 800;
}
}
.model-cont{
flex-grow: 1;
}
.modal-footer{
display: flex;
border-top: 1px solid #ccc;
justify-content: space-around;
}
}
}
@keyframes mode_animation {
0% {
background: rgba(0, 0, 0, 0);
}
25% {
background: rgba(0, 0, 0, 0.1);
}
50% {
background: rgba(0, 0, 0, 0.25);
}
75% {
background: rgba(0, 0, 0, 0.35);
}
100% {
background: rgba(0, 0, 0, 0.45);
}
}

View File

@ -1,64 +0,0 @@
import React, { ReactNode, useEffect, useState } from "react";
// 使用ReactDOM.createPortal 动态创建弹窗
// 可以插入到dom任意节点不限于父节点
import { CloseOutlined } from "@ant-design/icons";
import ReactDOM from "react-dom";
import "./dilog.less";
interface DilogModel {
show: boolean;
close: Function;
children: ReactNode;
maskClosable: boolean;
title?: string;
okText?: string;
}
const Dilog = (props: DilogModel) => {
const [isShow, showState] = useState(false);
useEffect(() => {
showState(props.show);
const onClick = (ev:MouseEvent) => {
if (ev.target === document.getElementsByClassName("modal")[0]) {
showState(false);
props.close();
}
};
const handleKeyword = (e:KeyboardEvent) => {
if (e.eventPhase === 27) {
showState(false);
props.close();
}
};
document.documentElement.addEventListener("click", onClick);
document.documentElement.addEventListener("keydown", handleKeyword);
return () => {
document.documentElement.removeEventListener("click", onClick);
document.documentElement.removeEventListener("keydown", handleKeyword);
};
}, [props.show]);
const handleClose = () => {
showState(false);
props.close();
};
const childrens = (
<div className="modal">
<div className="modal-content">
<div className="modal-header">
<CloseOutlined className="close-btn" onClick={handleClose} />
</div>
<div className="model-cont">{props.children}</div>
<div className="modal-footer">
<button>{props.okText ?? "确认"}</button>
<button></button>
</div>
</div>
</div>
);
return isShow
? ReactDOM.createPortal(
childrens,
document.getElementById("root") as Element
)
: null;
};
export default Dilog;

View File

@ -45,9 +45,9 @@ const LayOut = (props: Store) => {
<Layout>
<Header style={headStyle}>
<div style={logoStyle}>logo</div>
<Dropdown menu={{ items }}>
{/* <Dropdown menu={{ items }}> */}
<Avatar icon={<UserOutlined />} />
</Dropdown>
{/* </Dropdown> */}
</Header>
<Layout>
<Sider
@ -65,7 +65,6 @@ const LayOut = (props: Store) => {
style={{ height: "100%", borderRight: 0 }}
items={items}
onClick={(e) => {
console.log(e);
nav(e.key);
}}
/>

View File

@ -1,4 +1,7 @@
export const items = [
import { ItemType, MenuItemType } from 'antd/es/menu/interface';
export const items:ItemType<MenuItemType>[] = [
{
key: "/",
label: `首页看板`,
@ -11,25 +14,49 @@ export const items = [
],
},
{
key: "/source",
label: `数据管理`,
key: "/sku",
label: `商品管理`,
children: [
{ label: "数据管理", key: "/source/list" },
{ key: "/sku/list", label: `商品列表` },
{ key: "/sku/cat", label: `商品分类` },
{ key: "/sku/spec", label: `商品规格` },
{ key: "/sku/brand", label: `商品品牌` },
],
},
{
key: "/permission",
key: "/order",
label: `订单管理`,
children: [
{ key: "/order/list", label: `订单列表` },
],
},
{
key: "/rbac",
label: `权限管理`,
children: [
{ label: `角色管理`, key: "/permission/role" },
{ label: `菜单管理`, key: "/permission/menu" },
{ label: `角色管理`, key: "/rbac/role" },
{ label: `菜单管理`, key: "/rbac/menu" },
{ label: `部门管理`, key: "/rbac/dep" },
{ label: `机构管理`, key: "/rbac/org" },
{ label: `员工管理`, key: "/rbac/org1" },
],
},
{
key: "/city",
label: `区域管理`,
children: [
{ label: `区域列表`, key: "/city/list" },
],
},
{
key: "/sys",
label: `系统管理`,
children: [
{ label: `部门管理`, key: "/dep" },
{ label: `部门管理`, key: "/sys/dep" },
{ label: `数据字典`, key: "/sys/keywod" },
{ label: `版本管理`, key: "/sys/version" },
{ label: `捐赠管理`, key: "/sys/don" },
{ label: `通告管理`, key: "/sys/notic" },
],
},
];

View File

@ -1,4 +1,4 @@
import { Button, Space } from "antd";
import { Space } from "antd";
import { inject, observer } from "mobx-react";
import { Store } from "antd/lib/form/interface";
import React from "react";
@ -7,11 +7,11 @@ import "./index.less";
const Dashbord = (props: Store) => {
return (
<div className="contentBox">
<Space direction="vertical" size="middle" style={{ display: "flex" }}>
<Button type="primary" onClick={() => props.usrStore.getUserList()}>
</Button>
</Space>
<Space
direction="vertical"
size="middle"
style={{ display: "flex" }}
></Space>
</div>
);
};

View File

@ -1,7 +1,6 @@
.login_model {
width: 100%;
height: 100%;
background-repeat: no-repeat;
background-size: 100% 100%;
display: flex;
align-items: center;
@ -18,15 +17,17 @@
height: 100%;
}
.login-wrapper {
background-color: #fff;
width: 35%;
height: 400px;
background-color: #ececec;
width: 40%;
border-radius: 15px;
padding: 0 50px;
padding: 50px;
position: relative;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
display: flex;
flex-direction: column;
align-items: center;
}
.header {
@ -53,11 +54,11 @@
.btn {
text-align: center;
cursor: pointer;
background-color: red;
background-color: blue;
color: #fff;
padding: 10px;
border-radius: 10px;
width: 100%;
width: 300px;
margin-top: 40px;
}

View File

@ -9,13 +9,15 @@ const Login = (props) => {
const formRef = React.useRef<FormInstance>(null);
const navigate = useNavigate();
const onFinish = async (values: any) => {
navigate("/", { replace: true });
return;
let status = await usrStore.login({
userName: values.account,
passWord: values.password,
});
if (status) {
usrStore.closeLoginDilog();
navigate("/user/list", { replace: true });
navigate("/", { replace: true });
}
};
const onFinishFailed = () => {};

11
src/pages/rbac/index.tsx Normal file
View File

@ -0,0 +1,11 @@
import { Outlet } from "react-router";
const Rbac = () => {
return (
<div>
<Outlet />
</div>
);
};
export default Rbac;

View File

@ -0,0 +1,9 @@
const Brand = () => {
return (
<div>
cat
</div>
);
};
export default Brand;

View File

@ -0,0 +1,9 @@
const Cat = () => {
return (
<div>
cat
</div>
);
};
export default Cat;

11
src/pages/sku/index.tsx Normal file
View File

@ -0,0 +1,11 @@
import { Outlet } from "react-router";
const Sku = () => {
return (
<div>
<Outlet />
</div>
);
};
export default Sku;

View File

@ -0,0 +1,9 @@
const Spec = () => {
return (
<div>
cat
</div>
);
};
export default Spec;

View File

@ -1,8 +0,0 @@
.contentBox{
overflow-y: auto;
height: 100%;
.tableName{
height: 100%;
overflow-y: auto;
}
}

View File

@ -1,50 +0,0 @@
import React, { useEffect, useState } from "react";
import { Space } from "antd";
import { Store } from "antd/lib/form/interface";
import { inject, observer } from "mobx-react";
import BTable from "@/components/b_table";
import "./source.less";
const Source = (props: Store) => {
const { sourceStore } = props;
const [coloums,setColumns] = useState([])
const [content,setContent] = useState([])
// 获取列表数据
useEffect(() => {
sourceStore.getHead().then((res)=>{
res.forEach(element => {
element.dataIndex = "dbs_"+element.identity.toLowerCase()
element.title = element.data_name
});
setColumns(res)
});
sourceStore.geContent().then((res)=>{
res.forEach(element => {
element.key = "dbs_"+element.identity
});
setContent(res)
});
}, [sourceStore]);
return (
<div className="contentBox">
<Space direction="vertical" size="middle" style={{ display: "flex" }}>
<BTable
store={sourceStore}
scroll={{ x: "max-content" }}
columns={coloums}
dataSource={content}
deleteCallback={(id) => {
sourceStore.deleteItem(id);
}}
actionCloumn={(e)=>{
}}
editCallback={(record) => {
}}
/>
</Space>
</div>
);
};
export default inject("sourceStore")(observer(Source));

View File

@ -1,22 +0,0 @@
import { FormType } from "@/components/form/interface";
import { UserDataType } from "@/model/userModel";
import { ColumnsType } from "antd/lib/table";
import dayjs from "dayjs";
export const defaultConfig = [
{
type: FormType.input,
label: "数据集名称",
name: "resource_name",
value: "",
rules: [{ required: true, message: "请输入用户名称!" }],
},
];
export const columns: ColumnsType<UserDataType> = [
{
title: "数据集名称",
dataIndex: "resource_name",
width: 200,
},
];

View File

@ -3,9 +3,8 @@ import LayOut from "@/components/layout/layout";
import Login from "@/pages/login/login";
import User from "@/pages/user/user";
import Dashbord from "@/pages/dashbord";
import Source from "@/pages/source/source";
import Menu from "@/pages/menu/menu";
import Role from "@/pages/role/role";
import { rbac } from "./routers/rbac_router";
import { sku } from "./routers/sku_router";
const routers = createHashRouter([
{
@ -22,21 +21,8 @@ const routers = createHashRouter([
index: true,
element: <User />,
},
{
path: "/source/list",
index: true,
element: <Source />,
},
{
path: "/permission/menu",
index: true,
element: <Menu />,
},
{
path: "/permission/role",
index: true,
element: <Role />,
},
...rbac,
...sku
],
},
{

View File

@ -0,0 +1,21 @@
import Rbac from "@/pages/rbac";
import Menu from "@/pages/rbac/menu";
import Role from "@/pages/rbac/role";
export const rbac = [
{
path: "/rbac",
element: <Rbac />,
children: [
{
path: "/rbac/menu",
index: true,
element: <Menu />,
},
{
path: "/rbac/role",
index: true,
element: <Role />,
},
],
},
];

View File

@ -0,0 +1,33 @@
import Menu from "@/pages/rbac/menu";
import Sku from "@/pages/sku";
import Brand from "@/pages/sku/brand";
import Cat from "@/pages/sku/cat";
import Spec from "@/pages/sku/spec";
export const sku = [
{
path: "/sku",
element: <Sku />,
children: [
{
path: "/sku/list",
index: true,
element: <Menu />,
},
{
path: "/sku/cat",
index: true,
element: <Cat />,
},
{
path: "/sku/spec",
index: true,
element: <Spec />,
},
{
path: "/sku/brand",
index: true,
element: <Brand />,
},
],
},
];

View File

@ -1,7 +1,6 @@
import store from "@/store";
import Config from "@/util/config";
import axios, { AxiosResponse } from "axios";
// import { baseHttp } from '@/service/base';
// 添加请求拦截器
axios.defaults.headers.common["Content-Type"] = "application/json; charset=utf8";
axios.defaults.headers.common["X-Requested-With"] = "XMLHttpRequest";
@ -19,16 +18,16 @@ axios.interceptors.request.use((config) => {
// 添加响应拦截器
axios.interceptors.response.use((res: AxiosResponse) => {
if (res.data?.status === 401) {
store.usrStore.openLoginDilog()
store.usrStore.logOut()
window.location.href = '#/login'
// store.usrStore.openLoginDilog()
// store.usrStore.logOut()
// window.location.href = '#/login'
}
return res;
}, (err) => {
if (err.status === 401) {
store.usrStore.openLoginDilog()
store.usrStore.logOut()
window.location.href = '#/login'
// store.usrStore.openLoginDilog()
// store.usrStore.logOut()
// window.location.href = '#/login'
}
return Promise.reject(err);
});

View File

@ -1,10 +0,0 @@
class SourceConfig {
static ADD: string = "/desc";
static EDIT: string = "/desc";
static LIST: string = "/desc/content";
static DELETE: string = "/desc";
static Headers: string = "/desc/header";
static Content: string = "/desc/content";
}
export default SourceConfig;

View File

@ -1,5 +1,5 @@
class UserConfig {
static LOGINURI: string = "/anth/login/pc"
static LOGINURI: string = "/anth/login"
static ADD: string = "/user";
static EDIT: string = "/user";
static LIST: string = "/user/list";

View File

@ -1,9 +1,7 @@
import usrStore from '@/store/user'
import sourceStore from '@/store/source';
const store = {
usrStore,
sourceStore
};
export default store;

View File

@ -1,41 +0,0 @@
import { action, makeObservable, observable } from "mobx";
import BaseStore from "./baseStore";
import { UserDataType } from "@/model/userModel";
import SourceConfig from "@/service/source_config";
import { base } from "@/service/base";
import { message } from "antd";
class SourceStore extends BaseStore<UserDataType> {
headlist =[]
contentList =[]
constructor() {
super(SourceConfig)
makeObservable(this, {
getHead:action,
headlist:observable,
contentList:observable
})
}
async getHead(){
let res = await base.get(SourceConfig.Headers, {})
if (res.code !== 200) {
message.error(res.msg)
return false
}
this.headlist = res.data.record;
return res.data.record;
}
async geContent(){
let res = await base.get(SourceConfig.Content, {})
if (res.code !== 0) {
message.error(res.msg)
return false
}
this.contentList = res.data;
return res.data;
}
}
const sourceStore = new SourceStore();
export default sourceStore;

View File

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