Compare commits
10 Commits
21805d5d4b
...
024df07314
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
024df07314 | ||
|
|
49600e8da0 | ||
|
|
cd371a49df | ||
|
|
b6b1732fcd | ||
|
|
b12519b330 | ||
|
|
7c72dcd434 | ||
|
|
07af30b649 | ||
|
|
61c6a934ca | ||
|
|
b99fb241fe | ||
|
|
2057e1ea0f |
4
.env
4
.env
@@ -1,5 +1,5 @@
|
||||
# 项目版本号
|
||||
VITE_VERSION=2.2.1
|
||||
VITE_VERSION=2.3.3
|
||||
|
||||
# 项目后端API地址
|
||||
VITE_PROJECT_API=https://你的后端域名/api
|
||||
@@ -11,7 +11,7 @@ VITE_BAIDU_TONGJI_ACCESS_TOKEN=
|
||||
|
||||
# 星火AI相关配置(可选)
|
||||
# 配置教程:https://docs.liuyuyang.net/docs/项目部署/API/星火大模型.html
|
||||
VITE_AI_APIPassword=
|
||||
VITE_AI_APIPASSWORD=
|
||||
VITE_AI_MODEL=lite
|
||||
|
||||
# 高德地图Web API
|
||||
|
||||
@@ -80,7 +80,7 @@ VITE_BAIDU_TONGJI_ACCESS_TOKEN=
|
||||
VITE_BAIDU_TONGJI_REFRESH_TOKEN=
|
||||
|
||||
# 星火AI相关配置
|
||||
VITE_AI_APIPassword=
|
||||
VITE_AI_APIPASSWORD=
|
||||
VITE_AI_MODEL=
|
||||
```
|
||||
|
||||
|
||||
6616
pnpm-lock.yaml
generated
Normal file
6616
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,7 @@ const DefaultLayout: React.FC<{ children: ReactNode }> = ({ children }) => {
|
||||
const [sidebarOpen, setSidebarOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<div className="dark:bg-boxdark-2 dark:text-bodydark">
|
||||
<div className="dark:bg-[#1A222C] dark:text-bodydark">
|
||||
{/* <!-- ===== Page Wrapper Start ===== --> */}
|
||||
<div className="flex h-screen overflow-hidden">
|
||||
{/* <!-- ===== Sidebar Start ===== --> */}
|
||||
|
||||
@@ -27,11 +27,12 @@ export default () => {
|
||||
const { RangePicker } = DatePicker;
|
||||
|
||||
const getArticleList = async () => {
|
||||
setLoading(true);
|
||||
|
||||
try {
|
||||
setLoading(true);
|
||||
|
||||
const { data } = await getArticleListAPI();
|
||||
setArticleList(data);
|
||||
|
||||
setLoading(false);
|
||||
} catch (error) {
|
||||
setLoading(false);
|
||||
@@ -39,9 +40,9 @@ export default () => {
|
||||
};
|
||||
|
||||
const delArticleData = async (id: number) => {
|
||||
setLoading(true);
|
||||
|
||||
try {
|
||||
setLoading(true);
|
||||
|
||||
// 普通删除:可从回收站恢复
|
||||
await delArticleDataAPI(id, true);
|
||||
await getArticleList();
|
||||
@@ -151,9 +152,9 @@ export default () => {
|
||||
];
|
||||
|
||||
const onFilterSubmit = async (values: FilterForm) => {
|
||||
setLoading(true)
|
||||
|
||||
try {
|
||||
setLoading(true)
|
||||
|
||||
const query: FilterArticle = {
|
||||
key: values.title,
|
||||
cateIds: values.cateIds,
|
||||
@@ -166,6 +167,7 @@ export default () => {
|
||||
|
||||
const { data } = await getArticleListAPI({ query });
|
||||
setArticleList(data);
|
||||
|
||||
setLoading(false)
|
||||
} catch (error) {
|
||||
setLoading(false)
|
||||
|
||||
@@ -25,6 +25,7 @@ const CatePage = () => {
|
||||
const { data } = await getCateListAPI();
|
||||
data.sort((a, b) => a.order - b.order)
|
||||
setList(data);
|
||||
|
||||
setLoading(false)
|
||||
} catch (error) {
|
||||
setLoading(false)
|
||||
@@ -46,14 +47,16 @@ const CatePage = () => {
|
||||
|
||||
const editCateData = async (id: number) => {
|
||||
try {
|
||||
setEditLoading(true)
|
||||
|
||||
setIsMethod("edit");
|
||||
setIsModelOpen(true);
|
||||
setEditLoading(true)
|
||||
|
||||
const { data } = await getCateDataAPI(id);
|
||||
setIsCateShow(data.type === "cate" ? false : true);
|
||||
setCate(data);
|
||||
form.setFieldsValue(data);
|
||||
|
||||
setEditLoading(false)
|
||||
} catch (error) {
|
||||
setEditLoading(false)
|
||||
@@ -61,9 +64,9 @@ const CatePage = () => {
|
||||
};
|
||||
|
||||
const delCateData = async (id: number) => {
|
||||
setLoading(true)
|
||||
|
||||
try {
|
||||
setLoading(true)
|
||||
|
||||
await delCateDataAPI(id);
|
||||
await getCateList();
|
||||
message.success('🎉 删除分类成功');
|
||||
|
||||
@@ -30,21 +30,20 @@ export default () => {
|
||||
|
||||
const getCommentList = async () => {
|
||||
try {
|
||||
setLoading(true)
|
||||
const { data } = await getCommentListAPI();
|
||||
setList(data)
|
||||
setLoading(false)
|
||||
} catch (error) {
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
setLoading(true)
|
||||
getCommentList();
|
||||
}, []);
|
||||
|
||||
const columns: ColumnsType = [
|
||||
const columns: ColumnsType<Comment> = [
|
||||
{
|
||||
title: 'ID',
|
||||
dataIndex: 'id',
|
||||
@@ -61,7 +60,7 @@ export default () => {
|
||||
dataIndex: 'content',
|
||||
key: 'content',
|
||||
width: 400,
|
||||
render: (text: string, record) => <span className="hover:text-primary cursor-pointer line-clamp-2" onClick={() => {
|
||||
render: (text: string, record: Comment) => <span className="hover:text-primary cursor-pointer line-clamp-2" onClick={() => {
|
||||
setComment(record)
|
||||
setIsCommentModalOpen(true)
|
||||
}}>{text}</span>
|
||||
@@ -150,9 +149,9 @@ export default () => {
|
||||
const [replyInfo, setReplyInfo] = useState("")
|
||||
const [isReplyModalOpen, setIsReplyModalOpen] = useState(false);
|
||||
const handleReply = async () => {
|
||||
setBtnLoading(true)
|
||||
|
||||
try {
|
||||
setBtnLoading(true)
|
||||
|
||||
await addCommentDataAPI({
|
||||
avatar: user.avatar,
|
||||
url: web.url,
|
||||
@@ -169,6 +168,8 @@ export default () => {
|
||||
message.success('🎉 回复评论成功');
|
||||
setIsReplyModalOpen(false)
|
||||
setReplyInfo("")
|
||||
|
||||
setBtnLoading(true)
|
||||
} catch (error) {
|
||||
setBtnLoading(false)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
import { Button, Card, Drawer, Dropdown, MenuProps, message } from 'antd';
|
||||
import { Button, Card, Drawer, Dropdown, MenuProps, message, Spin } from 'antd';
|
||||
|
||||
import Title from '@/components/Title';
|
||||
import Editor from './components/Editor';
|
||||
@@ -32,19 +32,20 @@ export default () => {
|
||||
// 获取文章数据
|
||||
const getArticleData = async () => {
|
||||
try {
|
||||
setLoading(true)
|
||||
|
||||
const { data } = await getArticleDataAPI(id)
|
||||
setData(data)
|
||||
setContent(data.content)
|
||||
|
||||
setLoading(false)
|
||||
} catch (error) {
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
// 回显数据
|
||||
useEffect(() => {
|
||||
setLoading(true)
|
||||
setPublishOpen(false)
|
||||
|
||||
// 有Id就回显指定的数据
|
||||
@@ -93,14 +94,14 @@ export default () => {
|
||||
|
||||
// 解析接口数据
|
||||
const parsingData = async (command: string) => {
|
||||
setLoading(true)
|
||||
|
||||
try {
|
||||
setLoading(true)
|
||||
|
||||
const res = await fetch(`/ai/v1/chat/completions`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": `Bearer ${import.meta.env.VITE_AI_APIPassword}`
|
||||
"Authorization": `Bearer ${import.meta.env.VITE_AI_APIPASSWORD}`
|
||||
},
|
||||
body: JSON.stringify({
|
||||
model: import.meta.env.VITE_AI_MODEL,
|
||||
@@ -142,12 +143,12 @@ export default () => {
|
||||
|
||||
// 保留最后一行未处理的数据
|
||||
receivedText = lines[lines.length - 1];
|
||||
|
||||
setLoading(false)
|
||||
}
|
||||
} catch (error) {
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
// AI功能
|
||||
@@ -193,19 +194,21 @@ export default () => {
|
||||
</div>
|
||||
</Title>
|
||||
|
||||
<Card loading={loading} className={`${titleSty} overflow-hidden rounded-xl min-h-[calc(100vh-180px)]`}>
|
||||
<Editor value={content} onChange={(value) => setContent(value)} />
|
||||
<Spin spinning={loading}>
|
||||
<Card className={`${titleSty} overflow-hidden rounded-xl min-h-[calc(100vh-180px)]`}>
|
||||
<Editor value={content} onChange={(value) => setContent(value)} />
|
||||
|
||||
<Drawer
|
||||
title={(id && !isDraftParams) ? "编辑文章" : "发布文章"}
|
||||
placement="right"
|
||||
size='large'
|
||||
onClose={() => setPublishOpen(false)}
|
||||
open={publishOpen}
|
||||
>
|
||||
<PublishForm data={data} closeModel={() => setPublishOpen(false)} />
|
||||
</Drawer>
|
||||
</Card >
|
||||
<Drawer
|
||||
title={(id && !isDraftParams) ? "编辑文章" : "发布文章"}
|
||||
placement="right"
|
||||
size='large'
|
||||
onClose={() => setPublishOpen(false)}
|
||||
open={publishOpen}
|
||||
>
|
||||
<PublishForm data={data} closeModel={() => setPublishOpen(false)} />
|
||||
</Drawer>
|
||||
</Card >
|
||||
</Spin>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -32,9 +32,9 @@ export default () => {
|
||||
}
|
||||
|
||||
const onSubmit = async () => {
|
||||
setLoading(true)
|
||||
|
||||
try {
|
||||
setLoading(true)
|
||||
|
||||
const data = {
|
||||
content,
|
||||
images: JSON.stringify(imageList),
|
||||
@@ -52,29 +52,29 @@ export default () => {
|
||||
await addRecordDataAPI(data)
|
||||
}
|
||||
|
||||
setLoading(false)
|
||||
navigate("/record")
|
||||
} catch (error) {
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
const getRecordData = async () => {
|
||||
try {
|
||||
setLoading(true)
|
||||
|
||||
const { data } = await getRecordDataAPI(id)
|
||||
setContent(data.content)
|
||||
setImageList(JSON.parse(data.images as string))
|
||||
|
||||
setLoading(false)
|
||||
} catch (error) {
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
// 回显数据
|
||||
useEffect(() => {
|
||||
setLoading(true)
|
||||
// 有Id就回显指定的数据
|
||||
if (id) getRecordData()
|
||||
}, [id])
|
||||
@@ -145,7 +145,7 @@ export default () => {
|
||||
placeholder="记录此刻!"
|
||||
value={content}
|
||||
onChange={(e) => setContent(e.target.value)}
|
||||
className="w-full p-4 border-2 border-[#eee] dark:border-strokedark text-base rounded-md"
|
||||
className="w-full p-4 border-2 border-[#eee] dark:bg-boxdark-2 dark:border-transparent text-base rounded-md"
|
||||
/>
|
||||
|
||||
<div className="absolute bottom-4 left-4 flex items-end space-x-3 max-w-[calc(100%-80px)]">
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
export interface Result {
|
||||
timeSpan: string[];
|
||||
fields: string[];
|
||||
items: [
|
||||
string[][],
|
||||
number[][],
|
||||
any[],
|
||||
any[]
|
||||
];
|
||||
}
|
||||
|
||||
export interface MonthlySums {
|
||||
[key: string]: {
|
||||
pv: number;
|
||||
ip: number;
|
||||
};
|
||||
}
|
||||
|
||||
export interface ChartOneState {
|
||||
series: {
|
||||
name: string;
|
||||
data: number[];
|
||||
}[];
|
||||
}
|
||||
@@ -67,7 +67,7 @@ export default () => {
|
||||
const siteId = import.meta.env.VITE_BAIDU_TONGJI_SITE_ID;
|
||||
const token = import.meta.env.VITE_BAIDU_TONGJI_ACCESS_TOKEN;
|
||||
|
||||
const response = await fetch(`/api/rest/2.0/tongji/report/getData?access_token=${token}&site_id=${siteId}&start_date=${date}&end_date=${date}&metrics=new_visitor_count%2Cnew_visitor_ratio&method=trend%2Ftime%2Fa&gran=day&area=`);
|
||||
const response = await fetch(`/baidu/rest/2.0/tongji/report/getData?access_token=${token}&site_id=${siteId}&start_date=${date}&end_date=${date}&metrics=new_visitor_count%2Cnew_visitor_ratio&method=trend%2Ftime%2Fa&gran=day&area=`);
|
||||
const data = await response.json();
|
||||
const { result } = data;
|
||||
|
||||
@@ -88,8 +88,8 @@ export default () => {
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<Spin spinning={loading}>
|
||||
<div className="sm:px-7.5 col-span-12 rounded-lg border border-stroke bg-white px-5 pb-5 pt-7.5 shadow-default dark:border-strokedark dark:bg-boxdark xl:col-span-4">
|
||||
<div className="sm:px-7.5 col-span-12 rounded-lg border border-stroke bg-white px-5 pb-5 pt-7.5 shadow-default dark:border-strokedark dark:bg-boxdark xl:col-span-4">
|
||||
<Spin spinning={loading}>
|
||||
<div className="mb-3 justify-between gap-4 sm:flex">
|
||||
<div>
|
||||
<h5 className="text-xl font-semibold text-black dark:text-white">
|
||||
@@ -100,11 +100,7 @@ export default () => {
|
||||
|
||||
<div className="mb-2">
|
||||
<div id="chartThree" className="mx-auto flex justify-center">
|
||||
<ReactApexChart
|
||||
options={options}
|
||||
series={state.series}
|
||||
type="donut"
|
||||
/>
|
||||
<ReactApexChart options={options} series={state.series} type="donut" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -129,7 +125,7 @@ export default () => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Spin>
|
||||
</Spin>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -2,9 +2,32 @@ import { useEffect, useState, useCallback, useMemo } from 'react';
|
||||
import { Spin } from 'antd';
|
||||
import { ApexOptions } from 'apexcharts';
|
||||
import ReactApexChart from 'react-apexcharts';
|
||||
import { MonthlySums, ChartOneState } from './type';
|
||||
import dayjs from 'dayjs';
|
||||
import { Result } from '../../type';
|
||||
|
||||
interface Result {
|
||||
timeSpan: string[];
|
||||
fields: string[];
|
||||
items: [
|
||||
string[][],
|
||||
number[][],
|
||||
any[],
|
||||
any[]
|
||||
];
|
||||
}
|
||||
|
||||
interface MonthlySums {
|
||||
[key: string]: {
|
||||
pv: number;
|
||||
ip: number;
|
||||
};
|
||||
}
|
||||
|
||||
interface ChartOneState {
|
||||
series: {
|
||||
name: string;
|
||||
data: number[];
|
||||
}[];
|
||||
}
|
||||
|
||||
export default () => {
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
@@ -124,26 +147,26 @@ export default () => {
|
||||
|
||||
// 获取统计数据
|
||||
const getDataList = useCallback(async () => {
|
||||
setLoading(true)
|
||||
|
||||
try {
|
||||
setLoading(true)
|
||||
|
||||
const siteId = import.meta.env.VITE_BAIDU_TONGJI_SITE_ID;
|
||||
const token = import.meta.env.VITE_BAIDU_TONGJI_ACCESS_TOKEN;
|
||||
|
||||
const response = await fetch(`/api/rest/2.0/tongji/report/getData?access_token=${token}&site_id=${siteId}&start_date=${startDate}&end_date=${endDate}&metrics=pv_count%2Cip_count&method=overview%2FgetTimeTrendRpt`);
|
||||
const response = await fetch(`/baidu/rest/2.0/tongji/report/getData?access_token=${token}&site_id=${siteId}&start_date=${startDate}&end_date=${endDate}&metrics=pv_count%2Cip_count&method=overview%2FgetTimeTrendRpt`);
|
||||
const data = await response.json();
|
||||
const { result } = data;
|
||||
setResult(result);
|
||||
|
||||
setLoading(false);
|
||||
} catch (error) {
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
setLoading(false);
|
||||
}, [startDate, endDate]);
|
||||
|
||||
useEffect(() => {
|
||||
getDataList();
|
||||
}, [getDataList]);
|
||||
}, []);
|
||||
|
||||
// 切换不同范围的数据
|
||||
const scopeData = useMemo(() => {
|
||||
@@ -199,6 +222,10 @@ export default () => {
|
||||
case "year":
|
||||
const yearlySums: { [year: string]: { pv: number, ip: number } } = {};
|
||||
|
||||
console.log(result.items);
|
||||
console.log(result.items[0]);
|
||||
|
||||
|
||||
result.items[0].forEach((dateArray: string[], index: number) => {
|
||||
const date: string = dateArray[0];
|
||||
const [year, month, day] = date.split('/');
|
||||
@@ -239,6 +266,7 @@ export default () => {
|
||||
// 当数据发生变化时,更新图表选项和状态
|
||||
useEffect(() => {
|
||||
setLoading(true)
|
||||
|
||||
setOptions((data) => ({
|
||||
...data,
|
||||
xaxis: { ...options.xaxis, categories: scopeData.categories || [] }
|
||||
@@ -304,7 +332,7 @@ export default () => {
|
||||
</div>
|
||||
|
||||
<div className="flex w-full max-w-45 justify-end">
|
||||
<div className="inline-flex items-center rounded-md bg-whiter p-1.5 dark:bg-meta-4">
|
||||
<div className="inline-flex items-center rounded-md bg-whiter p-1.5 dark:bg-meta-4 space-x-1">
|
||||
<button className={`rounded py-1 px-3 text-xs font-medium text-black hover:bg-white hover:shadow-card dark:bg-meta-4 dark:text-white dark:hover:bg-boxdark ${scope === "day" ? "bg-white dark:!bg-[#4e5969] shadow-card" : ""}`} onClick={() => handleScopeChange("day")}>
|
||||
天
|
||||
</button>
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
export interface MonthlySums {
|
||||
[key: string]: {
|
||||
pv: number;
|
||||
ip: number;
|
||||
};
|
||||
}
|
||||
|
||||
export interface ChartOneState {
|
||||
series: {
|
||||
name: string;
|
||||
data: number[];
|
||||
}[];
|
||||
}
|
||||
@@ -31,9 +31,9 @@ export default () => {
|
||||
|
||||
// 获取统计数据
|
||||
const getDataList = async () => {
|
||||
setLoading(true)
|
||||
|
||||
try {
|
||||
setLoading(true)
|
||||
|
||||
const siteId = import.meta.env.VITE_BAIDU_TONGJI_SITE_ID;
|
||||
const token = import.meta.env.VITE_BAIDU_TONGJI_ACCESS_TOKEN;
|
||||
|
||||
@@ -78,11 +78,10 @@ export default () => {
|
||||
|
||||
setStats({ pv, ip, bounce: (bounce / count) || 0, avgTime: formatTime(avgTime / count) || "00:00:00" })
|
||||
|
||||
setLoading(false)
|
||||
} catch (error) {
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
setLoading(false)
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
10
src/pages/Dashboard/components/Stats/type.d.ts
vendored
10
src/pages/Dashboard/components/Stats/type.d.ts
vendored
@@ -1,10 +0,0 @@
|
||||
export interface Result {
|
||||
timeSpan: string[];
|
||||
fields: string[];
|
||||
items: [
|
||||
string[][],
|
||||
number[][],
|
||||
any[],
|
||||
any[]
|
||||
];
|
||||
}
|
||||
@@ -25,24 +25,25 @@ export default () => {
|
||||
|
||||
const getArticleList = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
|
||||
const { data } = await getArticleListAPI({ query: { isDel: 1 } });
|
||||
setArticleList(data as Article[]);
|
||||
setArticleList(data);
|
||||
|
||||
setLoading(false);
|
||||
} catch (error) {
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setLoading(true);
|
||||
getArticleList()
|
||||
}, []);
|
||||
|
||||
const delArticleData = async (id: number) => {
|
||||
setLoading(true);
|
||||
|
||||
try {
|
||||
setLoading(true);
|
||||
|
||||
// 严格删除:彻底从数据库删除,无法恢复
|
||||
await delArticleDataAPI(id);
|
||||
await getArticleList();
|
||||
@@ -55,12 +56,14 @@ export default () => {
|
||||
};
|
||||
|
||||
const reductionArticleData = async (id: number) => {
|
||||
setLoading(true);
|
||||
|
||||
try {
|
||||
setLoading(true);
|
||||
|
||||
await reductionArticleDataAPI(id)
|
||||
navigate("/article")
|
||||
notification.success({ message: '🎉 还原文章成功' })
|
||||
navigate("/article")
|
||||
|
||||
setLoading(false)
|
||||
} catch (error) {
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
@@ -23,23 +23,25 @@ export default () => {
|
||||
|
||||
const getArticleList = async () => {
|
||||
try {
|
||||
setLoading(true)
|
||||
|
||||
const { data } = await getArticleListAPI({ query: { isDraft: 1 } });
|
||||
setArticleList(data as Article[]);
|
||||
|
||||
setLoading(false)
|
||||
} catch (error) {
|
||||
setLoading(false);
|
||||
}
|
||||
setLoading(false)
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setLoading(true)
|
||||
getArticleList()
|
||||
}, []);
|
||||
|
||||
const delArticleData = async (id: number) => {
|
||||
setLoading(true);
|
||||
|
||||
try {
|
||||
setLoading(true);
|
||||
|
||||
await delArticleDataAPI(id);
|
||||
await getArticleList();
|
||||
form.resetFields()
|
||||
|
||||
@@ -36,56 +36,56 @@ export default () => {
|
||||
|
||||
// 获取目录列表
|
||||
const getDirList = async () => {
|
||||
setLoading(true)
|
||||
|
||||
try {
|
||||
setLoading(true)
|
||||
|
||||
const { data } = await getDirListAPI()
|
||||
setDirList(data)
|
||||
|
||||
setLoading(false)
|
||||
} catch (error) {
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
// 获取指定目录的文件列表
|
||||
const getFileList = async (dir: string) => {
|
||||
setLoading(true)
|
||||
|
||||
try {
|
||||
setLoading(true)
|
||||
|
||||
const { data } = await getFileListAPI(dir)
|
||||
if (!fileList.length && !data.length) message.error("该目录中没有文件")
|
||||
setFileList(data)
|
||||
|
||||
setLoading(false)
|
||||
} catch (error) {
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
// 删除图片
|
||||
const onDeleteImage = async (data: File) => {
|
||||
setBtnLoading(true)
|
||||
|
||||
try {
|
||||
setBtnLoading(true)
|
||||
|
||||
await delFileDataAPI(data.url)
|
||||
await getFileList(dirName)
|
||||
message.success("🎉 删除图片成功")
|
||||
setFile({} as File)
|
||||
setOpenFileInfoDrawer(false)
|
||||
setOpenFilePreviewDrawer(false)
|
||||
|
||||
setBtnLoading(false)
|
||||
} catch (error) {
|
||||
setBtnLoading(false)
|
||||
}
|
||||
|
||||
setBtnLoading(false)
|
||||
}
|
||||
|
||||
// 下载图片
|
||||
const onDownloadImage = (data: File) => {
|
||||
setDownloadLoading(true)
|
||||
|
||||
try {
|
||||
setDownloadLoading(true)
|
||||
|
||||
fetch(data.url)
|
||||
.then((response) => response.blob())
|
||||
.then((blob) => {
|
||||
@@ -98,11 +98,11 @@ export default () => {
|
||||
URL.revokeObjectURL(url);
|
||||
link.remove();
|
||||
});
|
||||
|
||||
setDownloadLoading(false)
|
||||
} catch (error) {
|
||||
setDownloadLoading(false)
|
||||
}
|
||||
|
||||
setDownloadLoading(false)
|
||||
};
|
||||
|
||||
// 打开目录
|
||||
@@ -199,22 +199,22 @@ export default () => {
|
||||
<div className='flex flex-col'>
|
||||
<div className='flex'>
|
||||
<span className='min-w-20 font-bold'>文件名称</span>
|
||||
<span className='text-[#333]'>{file.name}</span>
|
||||
<span className='text-[#333] dark:text-white'>{file.name}</span>
|
||||
</div>
|
||||
|
||||
<div className='flex'>
|
||||
<span className='min-w-20 font-bold'>文件类型</span>
|
||||
<span className='text-[#333]'>{file.type}</span>
|
||||
<span className='text-[#333] dark:text-white'>{file.type}</span>
|
||||
</div>
|
||||
|
||||
<div className='flex'>
|
||||
<span className='min-w-20 font-bold'>文件大小</span>
|
||||
<span className='text-[#333]'>{(file.size / 1048576).toFixed(2)}MB</span>
|
||||
<span className='text-[#333] dark:text-white'>{(file.size / 1048576).toFixed(2)}MB</span>
|
||||
</div>
|
||||
|
||||
<div className='flex'>
|
||||
<span className='min-w-20 font-bold'>文件链接</span>
|
||||
<span className='text-[#333] hover:text-primary cursor-pointer transition' onClick={async () => {
|
||||
<span className='text-[#333] dark:text-white hover:text-primary cursor-pointer transition' onClick={async () => {
|
||||
await navigator.clipboard.writeText(file.url)
|
||||
message.success("🎉 复制成功")
|
||||
}}>{file.url}</span>
|
||||
|
||||
@@ -129,9 +129,9 @@ export default () => {
|
||||
};
|
||||
|
||||
const editFootprintData = async (id: number) => {
|
||||
setEditLoading(true);
|
||||
|
||||
try {
|
||||
setEditLoading(true);
|
||||
|
||||
setIsMethod("edit");
|
||||
setIsModelOpen(true);
|
||||
|
||||
@@ -142,17 +142,17 @@ export default () => {
|
||||
|
||||
setFootprint(data);
|
||||
form.setFieldsValue(data);
|
||||
|
||||
setEditLoading(false);
|
||||
} catch (error) {
|
||||
setEditLoading(false);
|
||||
}
|
||||
|
||||
setEditLoading(false);
|
||||
};
|
||||
|
||||
|
||||
const onSubmit = async () => {
|
||||
setBtnLoading(true)
|
||||
|
||||
try {
|
||||
setBtnLoading(true)
|
||||
|
||||
form.validateFields().then(async (values: Footprint) => {
|
||||
values.createTime = values.createTime.valueOf()
|
||||
values.images = values.images ? (values.images as string).split("\n") : []
|
||||
@@ -166,6 +166,7 @@ export default () => {
|
||||
}
|
||||
|
||||
await getFootprintList();
|
||||
setBtnLoading(false)
|
||||
reset()
|
||||
});
|
||||
} catch (error) {
|
||||
@@ -176,9 +177,9 @@ export default () => {
|
||||
const closeModel = () => reset();
|
||||
|
||||
const onFilterSubmit = async (values: FilterForm) => {
|
||||
setLoading(true)
|
||||
|
||||
try {
|
||||
setLoading(true)
|
||||
|
||||
const query: FilterData = {
|
||||
key: values.address,
|
||||
startDate: values.createTime && values.createTime[0].valueOf() + '',
|
||||
@@ -187,18 +188,18 @@ export default () => {
|
||||
|
||||
const { data } = await getFootprintListAPI({ query });
|
||||
setFootprintList(data);
|
||||
|
||||
setLoading(false)
|
||||
} catch (error) {
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
// 通过详细地址获取纬度
|
||||
const getGeocode = async () => {
|
||||
setEditLoading(true)
|
||||
|
||||
try {
|
||||
setEditLoading(true)
|
||||
|
||||
const address = form.getFieldValue("address")
|
||||
|
||||
const { data } = await axios.get('https://restapi.amap.com/v3/geocode/geo', {
|
||||
@@ -215,17 +216,15 @@ export default () => {
|
||||
// 立即触发校验
|
||||
form.validateFields(['position']);
|
||||
|
||||
setEditLoading(false)
|
||||
|
||||
return data.geocodes[0].location;
|
||||
} else {
|
||||
message.warning('未找到该地址的经纬度');
|
||||
}
|
||||
|
||||
setEditLoading(false)
|
||||
} catch (error) {
|
||||
setEditLoading(false)
|
||||
}
|
||||
|
||||
setEditLoading(false)
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -24,6 +24,8 @@ export default () => {
|
||||
// 从github获取最近10次迭代记录
|
||||
const getCommitData = async (project: string) => {
|
||||
try {
|
||||
setLoading(true)
|
||||
|
||||
const res = await fetch(`https://api.github.com/repos/LiuYuYang01/${project}/commits?per_page=10`)
|
||||
const data = await res.json()
|
||||
const result = data?.map((item: Commit) => (
|
||||
@@ -47,11 +49,11 @@ export default () => {
|
||||
setServer_IterativeRecording(result)
|
||||
break;
|
||||
}
|
||||
|
||||
setLoading(false)
|
||||
} catch (error) {
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -7,19 +7,21 @@ import { loginDataAPI } from '@/api/User';
|
||||
import { useUserStore } from '@/stores';
|
||||
|
||||
export default () => {
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
const store = useUserStore();
|
||||
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
const [form] = useForm();
|
||||
|
||||
const [isPassVisible, setIsPassVisible] = useState(false);
|
||||
const store = useUserStore();
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
const returnUrl = new URLSearchParams(location.search).get('returnUrl') || '/';
|
||||
|
||||
const onSubmit = async () => {
|
||||
setLoading(true)
|
||||
|
||||
try {
|
||||
setLoading(true)
|
||||
|
||||
const values = await form.validateFields();
|
||||
const { data } = await loginDataAPI(values);
|
||||
|
||||
@@ -33,12 +35,11 @@ export default () => {
|
||||
description: `Hello ${data.user.name} 欢迎回来`,
|
||||
});
|
||||
|
||||
setLoading(false)
|
||||
navigate(returnUrl);
|
||||
} catch (error) {
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
setLoading(false)
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -86,25 +86,26 @@ export default () => {
|
||||
|
||||
const getOssList = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
|
||||
const { data } = await getOssListAPI();
|
||||
setOssList(data);
|
||||
|
||||
setLoading(false);
|
||||
} catch (error) {
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setLoading(true);
|
||||
getOssList();
|
||||
getOssPlatformList()
|
||||
}, []);
|
||||
|
||||
const enableOssData = async (id: number) => {
|
||||
setLoading(true)
|
||||
|
||||
try {
|
||||
setLoading(true)
|
||||
|
||||
await enableOssDataAPI(id);
|
||||
await getOssList();
|
||||
message.success('启用成功');
|
||||
@@ -114,9 +115,9 @@ export default () => {
|
||||
};
|
||||
|
||||
const disableOssData = async (id: number) => {
|
||||
setLoading(true)
|
||||
|
||||
try {
|
||||
setLoading(true)
|
||||
|
||||
await disableOssDataAPI(id);
|
||||
await getOssList();
|
||||
message.success('禁用成功');
|
||||
@@ -126,25 +127,25 @@ export default () => {
|
||||
};
|
||||
|
||||
const editOssData = async (record: Oss) => {
|
||||
setEditLoading(true)
|
||||
|
||||
try {
|
||||
setEditLoading(true)
|
||||
|
||||
setIsModalOpen(true);
|
||||
|
||||
const { data } = await getOssDataAPI(record.id)
|
||||
setOss(data);
|
||||
form.setFieldsValue(data);
|
||||
|
||||
setEditLoading(false)
|
||||
} catch (error) {
|
||||
setEditLoading(false)
|
||||
}
|
||||
|
||||
setEditLoading(false)
|
||||
};
|
||||
|
||||
const delOssData = async (id: number) => {
|
||||
setLoading(true);
|
||||
|
||||
try {
|
||||
setLoading(true);
|
||||
|
||||
await delOssDataAPI(id);
|
||||
await getOssList();
|
||||
message.success('🎉 删除存储配置成功');
|
||||
@@ -166,9 +167,9 @@ export default () => {
|
||||
};
|
||||
|
||||
const onSubmit = async () => {
|
||||
setBtnLoading(true);
|
||||
|
||||
try {
|
||||
setBtnLoading(true);
|
||||
|
||||
const values = await form.validateFields();
|
||||
|
||||
if (oss.id) {
|
||||
@@ -179,15 +180,14 @@ export default () => {
|
||||
message.success('🎉 新增存储配置成功');
|
||||
}
|
||||
|
||||
await getOssList();
|
||||
setIsModalOpen(false);
|
||||
getOssList();
|
||||
form.resetFields();
|
||||
|
||||
setBtnLoading(false);
|
||||
} catch (error) {
|
||||
setBtnLoading(false);
|
||||
}
|
||||
|
||||
setBtnLoading(false)
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -23,28 +23,31 @@ export default () => {
|
||||
|
||||
const getRecordList = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
|
||||
const { data } = await getRecordListAPI();
|
||||
setRecordList(data as Record[]);
|
||||
|
||||
setLoading(false);
|
||||
} catch (error) {
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setLoading(true);
|
||||
getRecordList()
|
||||
}, []);
|
||||
|
||||
const delRecordData = async (id: number) => {
|
||||
setLoading(true);
|
||||
|
||||
try {
|
||||
setLoading(true);
|
||||
|
||||
await delRecordDataAPI(id);
|
||||
await getRecordList();
|
||||
form.resetFields()
|
||||
notification.success({ message: '🎉 删除说说成功' })
|
||||
|
||||
setLoading(false);
|
||||
} catch (error) {
|
||||
setLoading(false);
|
||||
}
|
||||
@@ -116,9 +119,9 @@ export default () => {
|
||||
];
|
||||
|
||||
const onFilterSubmit = async (values: FilterForm) => {
|
||||
setLoading(true);
|
||||
|
||||
try {
|
||||
setLoading(true);
|
||||
|
||||
const query = {
|
||||
key: values.content,
|
||||
startDate: values.createTime && values.createTime[0].valueOf() + '',
|
||||
@@ -126,12 +129,12 @@ export default () => {
|
||||
}
|
||||
|
||||
const { data } = await getRecordListAPI({ query });
|
||||
setRecordList(data as Record[]);
|
||||
setRecordList(data);
|
||||
|
||||
setLoading(false);
|
||||
} catch (error) {
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -52,54 +52,56 @@ export default () => {
|
||||
// 获取角色列表
|
||||
const getRoleList = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
|
||||
const { data } = await getRoleListAPI();
|
||||
setRoleList(data as Role[]);
|
||||
|
||||
setLoading(false);
|
||||
} catch (error) {
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setLoading(true);
|
||||
getRoleList()
|
||||
getRouteList()
|
||||
}, []);
|
||||
|
||||
// 获取指定角色的路由列表
|
||||
const bindingRoute = async (record: Role) => {
|
||||
setEditLoading(true)
|
||||
|
||||
try {
|
||||
setEditLoading(true)
|
||||
|
||||
setIsModalOpen(true)
|
||||
|
||||
const { data } = await getRoleRouteListAPI(record.id);
|
||||
setTargetKeys(data.map(item => item.id) as number[])
|
||||
|
||||
setEditLoading(false)
|
||||
} catch (error) {
|
||||
setEditLoading(false)
|
||||
}
|
||||
|
||||
setEditLoading(false)
|
||||
}
|
||||
|
||||
const editRoleData = async (record: Role) => {
|
||||
setEditLoading(true);
|
||||
|
||||
try {
|
||||
setEditLoading(true);
|
||||
|
||||
const { data } = await getRoleDataAPI(record.id);
|
||||
setRole(data);
|
||||
form.setFieldsValue(data);
|
||||
|
||||
setEditLoading(false);
|
||||
} catch (error) {
|
||||
setEditLoading(false);
|
||||
}
|
||||
|
||||
setEditLoading(false);
|
||||
};
|
||||
|
||||
const delRoleData = async (id: number) => {
|
||||
setLoading(true);
|
||||
|
||||
try {
|
||||
setLoading(true);
|
||||
|
||||
await delRoleDataAPI(id);
|
||||
await getRoleList();
|
||||
message.success('🎉 删除角色成功');
|
||||
@@ -109,9 +111,9 @@ export default () => {
|
||||
};
|
||||
|
||||
const onSubmit = async () => {
|
||||
setBtnLoading(true)
|
||||
|
||||
try {
|
||||
setBtnLoading(true)
|
||||
|
||||
form.validateFields().then(async (values: Role) => {
|
||||
if (role.id) {
|
||||
await editRoleDataAPI({ ...role, ...values });
|
||||
@@ -126,11 +128,11 @@ export default () => {
|
||||
form.setFieldsValue({ name: '', description: '' })
|
||||
setRole({} as Role);
|
||||
});
|
||||
|
||||
setBtnLoading(false)
|
||||
} catch (error) {
|
||||
setBtnLoading(false)
|
||||
}
|
||||
|
||||
setBtnLoading(false)
|
||||
};
|
||||
|
||||
// 设置目标路由
|
||||
@@ -138,10 +140,11 @@ export default () => {
|
||||
|
||||
// 绑定路由
|
||||
const onBindingRouteSubmit = async () => {
|
||||
setBindingLoading(true);
|
||||
|
||||
try {
|
||||
setBindingLoading(true);
|
||||
|
||||
await bindingRouteAPI(role.id, targetKeys)
|
||||
setBindingLoading(false);
|
||||
message.success('🎉 绑定成功');
|
||||
// 刷新页面
|
||||
window.location.reload()
|
||||
|
||||
@@ -33,51 +33,54 @@ export default () => {
|
||||
|
||||
const getRouteList = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
|
||||
const { data } = await getRouteListAPI();
|
||||
setList(data);
|
||||
|
||||
setLoading(false);
|
||||
} catch (error) {
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setLoading(true);
|
||||
getRouteList();
|
||||
}, []);
|
||||
|
||||
const editRouteData = async (record: Route) => {
|
||||
setLoading(true)
|
||||
|
||||
try {
|
||||
setLoading(true)
|
||||
|
||||
const { data } = await getRouteDataAPI(record.id);
|
||||
setRoute(data);
|
||||
form.setFieldsValue(data);
|
||||
|
||||
setLoading(false)
|
||||
} catch (error) {
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
setLoading(false)
|
||||
};
|
||||
|
||||
const delRouteData = async (id: number) => {
|
||||
setLoading(true);
|
||||
|
||||
try {
|
||||
setLoading(true);
|
||||
|
||||
await delRouteDataAPI(id);
|
||||
await getRouteList();
|
||||
message.success('🎉 删除路由成功');
|
||||
|
||||
setLoading(false)
|
||||
} catch (error) {
|
||||
setLoading(false)
|
||||
}
|
||||
};
|
||||
|
||||
const onSubmit = async () => {
|
||||
setLoading(true);
|
||||
setBtnLoading(true)
|
||||
|
||||
try {
|
||||
setLoading(true);
|
||||
setBtnLoading(true)
|
||||
|
||||
form.validateFields().then(async (values: Route) => {
|
||||
if (route.id) {
|
||||
await editRouteDataAPI({ ...route, ...values });
|
||||
@@ -92,13 +95,13 @@ export default () => {
|
||||
form.setFieldsValue({ path: '', description: '' })
|
||||
setRoute({} as Route);
|
||||
});
|
||||
|
||||
setLoading(false)
|
||||
setBtnLoading(true)
|
||||
} catch (error) {
|
||||
setLoading(false)
|
||||
setBtnLoading(true)
|
||||
}
|
||||
|
||||
setLoading(false)
|
||||
setBtnLoading(true)
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -20,17 +20,18 @@ export default () => {
|
||||
|
||||
const getRssList = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
|
||||
const { data } = await getRssListAPI();
|
||||
setList(data);
|
||||
|
||||
setLoading(false);
|
||||
} catch (error) {
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setLoading(true);
|
||||
getRssList();
|
||||
}, []);
|
||||
|
||||
|
||||
@@ -19,25 +19,26 @@ export default () => {
|
||||
|
||||
const getUserData = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
|
||||
const { data } = await getUserDataAPI(store.user?.id);
|
||||
store.setUser(data);
|
||||
form.setFieldsValue(data);
|
||||
|
||||
setLoading(false);
|
||||
} catch (error) {
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setLoading(true);
|
||||
getUserData();
|
||||
}, []);
|
||||
|
||||
const onSubmit = async (values: UserForm) => {
|
||||
setLoading(true)
|
||||
|
||||
try {
|
||||
setLoading(true)
|
||||
|
||||
await editUserDataAPI({
|
||||
id: store.user.id, ...values,
|
||||
role: undefined
|
||||
|
||||
@@ -35,9 +35,9 @@ export default () => {
|
||||
};
|
||||
|
||||
const handleSubmit = async (values: EditUser) => {
|
||||
setLoading(true)
|
||||
|
||||
try {
|
||||
setLoading(true)
|
||||
|
||||
await editAdminPassAPI(values);
|
||||
|
||||
confirm({
|
||||
@@ -47,11 +47,11 @@ export default () => {
|
||||
onOk: store.quitLogin,
|
||||
cancelButtonProps: { style: { display: 'none' } }
|
||||
});
|
||||
|
||||
setLoading(false)
|
||||
} catch (error) {
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
setLoading(false)
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,49 +1,48 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Spin, Form, notification, Input, Button } from 'antd';
|
||||
import { LoadingOutlined } from '@ant-design/icons';
|
||||
import { Form, notification, Input, Button } from 'antd';
|
||||
import { Theme } from '@/types/app/project';
|
||||
import { editConfigDataAPI, getConfigDataAPI } from '@/api/Project';
|
||||
|
||||
const RecordTheme = () => {
|
||||
export default () => {
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
|
||||
const [form] = Form.useForm();
|
||||
|
||||
const getLayoutData = async () => {
|
||||
try {
|
||||
const { data } = await getConfigDataAPI<Theme>("layout");
|
||||
setLoading(true);
|
||||
|
||||
const { data } = await getConfigDataAPI<Theme>("layout");
|
||||
form.setFieldsValue({
|
||||
record_name: data.record_name,
|
||||
record_info: data.record_info
|
||||
});
|
||||
|
||||
setLoading(false);
|
||||
} catch (error) {
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setLoading(true);
|
||||
getLayoutData();
|
||||
}, []);
|
||||
|
||||
const editThemeData = async (values: { record_name: string, record_info: string }) => {
|
||||
setLoading(true);
|
||||
|
||||
try {
|
||||
setLoading(true);
|
||||
|
||||
await editConfigDataAPI("layout", values);
|
||||
|
||||
notification.success({
|
||||
message: '成功',
|
||||
description: '🎉 修改主题成功',
|
||||
});
|
||||
|
||||
setLoading(false);
|
||||
} catch (error) {
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -69,6 +68,4 @@ const RecordTheme = () => {
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default RecordTheme;
|
||||
};
|
||||
@@ -1,11 +1,11 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { notification, Divider, Input, Alert, Button, Spin, Form } from 'antd';
|
||||
import { PictureOutlined, LoadingOutlined, CloudUploadOutlined } from '@ant-design/icons';
|
||||
import { notification, Divider, Input, Alert, Button, Form } from 'antd';
|
||||
import { PictureOutlined, CloudUploadOutlined } from '@ant-design/icons';
|
||||
import { editConfigDataAPI, getConfigDataAPI } from '@/api/Project';
|
||||
import { Theme } from '@/types/app/project';
|
||||
import FileUpload from '@/components/FileUpload';
|
||||
|
||||
const SynthesisTheme = () => {
|
||||
export default () => {
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
|
||||
const [isModalOpen, setIsModalOpen] = useState<boolean>(false);
|
||||
@@ -22,6 +22,8 @@ const SynthesisTheme = () => {
|
||||
|
||||
const getLayoutData = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
|
||||
const { data } = await getConfigDataAPI<Theme>("layout");
|
||||
setTheme(data);
|
||||
|
||||
@@ -34,22 +36,21 @@ const SynthesisTheme = () => {
|
||||
covers: data.covers ? JSON.parse(data.covers).join("\n") : '',
|
||||
reco_article: data.reco_article ? JSON.parse(data.reco_article).join("\n") : '',
|
||||
});
|
||||
|
||||
setLoading(false);
|
||||
} catch (error) {
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setLoading(true);
|
||||
getLayoutData();
|
||||
}, []);
|
||||
|
||||
const editThemeData = async (values: any) => {
|
||||
setLoading(true);
|
||||
|
||||
try {
|
||||
setLoading(true);
|
||||
|
||||
const updatedLayout = {
|
||||
...theme,
|
||||
...values,
|
||||
@@ -64,11 +65,11 @@ const SynthesisTheme = () => {
|
||||
message: '成功',
|
||||
description: '🎉 修改主题成功',
|
||||
});
|
||||
|
||||
setLoading(false);
|
||||
} catch (error) {
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
const getFile = (name: string) => {
|
||||
@@ -198,6 +199,4 @@ const SynthesisTheme = () => {
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SynthesisTheme;
|
||||
};
|
||||
@@ -43,53 +43,54 @@ export default () => {
|
||||
|
||||
const getSwiperList = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
|
||||
const { data } = await getSwiperListAPI();
|
||||
setList(data as Swiper[]);
|
||||
|
||||
setLoading(false);
|
||||
} catch (error) {
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setLoading(true);
|
||||
getSwiperList();
|
||||
}, []);
|
||||
|
||||
const editSwiperData = async (record: Swiper) => {
|
||||
setEditLoading(true);
|
||||
setTab('operate');
|
||||
|
||||
try {
|
||||
setEditLoading(true);
|
||||
setTab('operate');
|
||||
|
||||
const { data } = await getSwiperDataAPI(record.id)
|
||||
setSwiper(data);
|
||||
form.setFieldsValue(record);
|
||||
|
||||
setEditLoading(false);
|
||||
} catch (error) {
|
||||
setEditLoading(false);
|
||||
}
|
||||
|
||||
setEditLoading(false);
|
||||
};
|
||||
|
||||
const delSwiperData = async (id: number) => {
|
||||
setBtnLoading(true);
|
||||
|
||||
try {
|
||||
setBtnLoading(true);
|
||||
|
||||
await delSwiperDataAPI(id);
|
||||
await getSwiperList();
|
||||
message.success('🎉 删除轮播图成功');
|
||||
|
||||
setBtnLoading(false);
|
||||
} catch (error) {
|
||||
setBtnLoading(false);
|
||||
}
|
||||
|
||||
setBtnLoading(false);
|
||||
};
|
||||
|
||||
const onSubmit = async () => {
|
||||
setBtnLoading(true)
|
||||
|
||||
try {
|
||||
setBtnLoading(true)
|
||||
|
||||
form.validateFields().then(async (values: Swiper) => {
|
||||
if (swiper.id) {
|
||||
await editSwiperDataAPI({ ...swiper, ...values });
|
||||
@@ -104,6 +105,8 @@ export default () => {
|
||||
form.resetFields();
|
||||
setSwiper({} as Swiper);
|
||||
})
|
||||
|
||||
setBtnLoading(false)
|
||||
} catch (error) {
|
||||
setBtnLoading(false)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { Table, Button, Form, Input, Popconfirm, message, Card } from 'antd';
|
||||
import { Table, Button, Form, Input, Popconfirm, message, Card, Spin } from 'antd';
|
||||
import { getTagListAPI, addTagDataAPI, editTagDataAPI, delTagDataAPI, getTagDataAPI } from '@/api/Tag';
|
||||
import { Tag } from '@/types/app/tag';
|
||||
import Title from '@/components/Title';
|
||||
@@ -8,6 +8,7 @@ import { ColumnsType } from 'antd/es/table';
|
||||
export default () => {
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const [btnLoading, setBtnLoading] = useState(false)
|
||||
const [editLoading, setEditLoading] = useState(false)
|
||||
|
||||
const [form] = Form.useForm();
|
||||
|
||||
@@ -32,38 +33,39 @@ export default () => {
|
||||
|
||||
const getTagList = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
|
||||
const { data } = await getTagListAPI();
|
||||
setList(data as Tag[]);
|
||||
|
||||
setLoading(false);
|
||||
} catch (error) {
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setLoading(true);
|
||||
getTagList();
|
||||
}, []);
|
||||
|
||||
const editTagData = async (record: Tag) => {
|
||||
setLoading(true);
|
||||
|
||||
try {
|
||||
setEditLoading(true);
|
||||
|
||||
const { data } = await getTagDataAPI(record.id)
|
||||
setTag(data);
|
||||
form.setFieldsValue(data);
|
||||
} catch (error) {
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
setLoading(false);
|
||||
setEditLoading(false);
|
||||
} catch (error) {
|
||||
setEditLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const delTagData = async (id: number) => {
|
||||
setLoading(true);
|
||||
|
||||
try {
|
||||
setLoading(true);
|
||||
|
||||
await delTagDataAPI(id);
|
||||
await getTagList();
|
||||
message.success('🎉 删除标签成功');
|
||||
@@ -73,10 +75,10 @@ export default () => {
|
||||
};
|
||||
|
||||
const onSubmit = async () => {
|
||||
setLoading(true);
|
||||
setBtnLoading(true);
|
||||
|
||||
try {
|
||||
setLoading(true);
|
||||
setBtnLoading(true);
|
||||
|
||||
form.validateFields().then(async (values: Tag) => {
|
||||
if (tag.id) {
|
||||
await editTagDataAPI({ ...tag, ...values });
|
||||
@@ -91,36 +93,42 @@ export default () => {
|
||||
form.setFieldsValue({ name: '' })
|
||||
setTag({} as Tag);
|
||||
});
|
||||
|
||||
setLoading(false);
|
||||
setBtnLoading(false);
|
||||
} catch (error) {
|
||||
setLoading(false);
|
||||
setBtnLoading(false);
|
||||
}
|
||||
|
||||
setBtnLoading(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Title value="标签管理" />
|
||||
|
||||
<div className='flex md:justify-between flex-col md:flex-row mx-auto mt-2'>
|
||||
<Card className="w-full md:w-[40%] h-[calc(100vh-180px)]">
|
||||
<Form
|
||||
form={form}
|
||||
layout="vertical"
|
||||
initialValues={tag}
|
||||
onFinish={onSubmit}
|
||||
size='large'
|
||||
>
|
||||
<Form.Item label="标签名称" name="name" rules={[{ required: true, message: '标签名称不能为空' }]}>
|
||||
<Input placeholder="请输入标签名称" />
|
||||
</Form.Item>
|
||||
<div className='flex md:justify-between flex-col md:flex-row mx-auto mt-2 h-[calc(100vh-180px)]'>
|
||||
<div className='w-full md:w-[40%]'>
|
||||
<Spin spinning={editLoading}>
|
||||
{/* <Card className="w-full md:w-[40%] h-46"> */}
|
||||
<Card className="w-full h-46">
|
||||
<Form
|
||||
form={form}
|
||||
layout="vertical"
|
||||
initialValues={tag}
|
||||
onFinish={onSubmit}
|
||||
size='large'
|
||||
>
|
||||
<Form.Item label="标签名称" name="name" rules={[{ required: true, message: '标签名称不能为空' }]}>
|
||||
<Input placeholder="请输入标签名称" />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item>
|
||||
<Button type="primary" htmlType="submit" loading={btnLoading} className="w-full">{tag.id ? '编辑标签' : '新增标签'}</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Card>
|
||||
<Form.Item>
|
||||
<Button type="primary" htmlType="submit" loading={btnLoading} className="w-full">{tag.id ? '编辑标签' : '新增标签'}</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Card>
|
||||
</Spin>
|
||||
</div>
|
||||
|
||||
<Card className="w-full md:w-[59%] [&>.ant-card-body]:!p-0 mt-2 md:mt-0">
|
||||
<Table
|
||||
|
||||
@@ -111,33 +111,31 @@ export default () => {
|
||||
|
||||
const getUserList = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
|
||||
const { data } = await getUserListAPI();
|
||||
setUserList(data as User[]);
|
||||
|
||||
setLoading(false);
|
||||
} catch (error) {
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
const getRoleList = async () => {
|
||||
const { data } = await getRoleListAPI();
|
||||
console.log(data);
|
||||
|
||||
setRoleList(data);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setLoading(true);
|
||||
getUserList();
|
||||
getRoleList()
|
||||
}, []);
|
||||
|
||||
const delUserData = async (id: number) => {
|
||||
setLoading(true);
|
||||
|
||||
try {
|
||||
setLoading(true);
|
||||
|
||||
await delUserDataAPI(id);
|
||||
await getUserList();
|
||||
notification.success({ message: '🎉 删除用户成功' });
|
||||
@@ -147,18 +145,18 @@ export default () => {
|
||||
};
|
||||
|
||||
const editUserData = async (id: number) => {
|
||||
setEditLoading(true);
|
||||
|
||||
try {
|
||||
setEditLoading(true);
|
||||
|
||||
setDrawerVisible(true);
|
||||
const { data } = await getUserDataAPI(id)
|
||||
setUser(data);
|
||||
form.setFieldsValue(data);
|
||||
|
||||
setEditLoading(false);
|
||||
} catch (error) {
|
||||
setEditLoading(false);
|
||||
}
|
||||
|
||||
setEditLoading(false);
|
||||
};
|
||||
|
||||
const reset = () => {
|
||||
@@ -167,9 +165,9 @@ export default () => {
|
||||
}
|
||||
|
||||
const onSubmit = async () => {
|
||||
setBtnLoading(true)
|
||||
|
||||
try {
|
||||
setBtnLoading(true)
|
||||
|
||||
form.validateFields().then(async (values: User) => {
|
||||
if (user.id) {
|
||||
await editUserDataAPI({ ...user, ...values });
|
||||
@@ -183,17 +181,17 @@ export default () => {
|
||||
setDrawerVisible(false);
|
||||
reset()
|
||||
})
|
||||
|
||||
setBtnLoading(false)
|
||||
} catch (error) {
|
||||
setBtnLoading(false)
|
||||
}
|
||||
|
||||
setBtnLoading(false)
|
||||
};
|
||||
|
||||
const onFilterSubmit = async (values: FilterForm) => {
|
||||
setLoading(true)
|
||||
|
||||
try {
|
||||
setLoading(true)
|
||||
|
||||
const query: FilterUser = {
|
||||
key: values.name,
|
||||
roleId: values.role,
|
||||
@@ -202,12 +200,12 @@ export default () => {
|
||||
}
|
||||
|
||||
const { data } = await getUserListAPI({ query });
|
||||
setUserList(data as User[]);
|
||||
setUserList(data);
|
||||
|
||||
setLoading(false)
|
||||
} catch (error) {
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -17,13 +17,15 @@ export default () => {
|
||||
|
||||
const getWallList = async () => {
|
||||
try {
|
||||
setLoading(true)
|
||||
|
||||
const { data } = await getWallListAPI();
|
||||
setList(data)
|
||||
|
||||
setLoading(false)
|
||||
} catch (error) {
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
const delWallData = async (id: number) => {
|
||||
@@ -48,12 +50,11 @@ export default () => {
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
setLoading(true)
|
||||
getWallList();
|
||||
getCateList()
|
||||
}, []);
|
||||
|
||||
const columns: ColumnsType = [
|
||||
const columns: ColumnsType<Wall> = [
|
||||
{
|
||||
title: 'ID',
|
||||
dataIndex: 'id',
|
||||
@@ -64,7 +65,7 @@ export default () => {
|
||||
title: '分类',
|
||||
dataIndex: 'cate',
|
||||
key: 'cate',
|
||||
render: ({ name }, { color }) => <Tag bordered={false} color={color} className='!text-[#565656]'>{name}</Tag>,
|
||||
render: ({ name }, { color }) => <Tag bordered={false} color={color} className='!text-[#565656] dark:!text-white'>{name}</Tag>,
|
||||
},
|
||||
{
|
||||
title: '名称',
|
||||
@@ -76,7 +77,7 @@ export default () => {
|
||||
dataIndex: 'content',
|
||||
key: 'content',
|
||||
width: 400,
|
||||
render: (text: string, record) => <span className="hover:text-primary cursor-pointer line-clamp-2" onClick={() => {
|
||||
render: (text: string, record: Wall) => <span className="hover:text-primary cursor-pointer line-clamp-2" onClick={() => {
|
||||
setWall(record)
|
||||
setIsModalOpen(true)
|
||||
}}>{text}</span>
|
||||
@@ -118,9 +119,9 @@ export default () => {
|
||||
const { RangePicker } = DatePicker;
|
||||
|
||||
const onFilterSubmit = async (values: FilterForm) => {
|
||||
setLoading(true)
|
||||
|
||||
try {
|
||||
setLoading(true)
|
||||
|
||||
const query: FilterWall = {
|
||||
key: values.content,
|
||||
cateId: values.cateId,
|
||||
@@ -130,11 +131,11 @@ export default () => {
|
||||
|
||||
const { data } = await getWallListAPI({ query });
|
||||
setList(data)
|
||||
|
||||
setLoading(false)
|
||||
} catch (error) {
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
1
src/pages/Web/assets/svg/group.svg
Normal file
1
src/pages/Web/assets/svg/group.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg t="1737289214739" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1760" width="200" height="200"><path d="M878.08 807.936l-192-92.16 8.192-190.464 194.56 82.432z" fill="#FF8F00" p-id="1761"></path><path d="M707.072 841.216l-186.88-96.256 165.888-29.184 192 92.16z" fill="#C16500" p-id="1762"></path><path d="M632.832 935.936l-183.296-101.888L459.264 481.28l188.416 82.944z" fill="#C16500" p-id="1763"></path><path d="M647.68 564.224L459.264 481.28l303.104-41.984 197.632 76.8z" fill="#FF8F00" p-id="1764"></path><path d="M647.68 564.224l312.832-48.128-19.968 357.376-306.688 62.464 13.824-371.712z m230.4 243.712l10.752-200.192-173.056 28.672-8.704 204.8 171.008-33.28" fill="#FFC107" p-id="1765"></path><path d="M650.752 479.232L461.824 400.896l10.24-371.2L665.6 87.04z" fill="#1E88E5" p-id="1766"></path><path d="M665.6 87.04L472.064 29.696 781.824 5.12l204.288 53.248z" fill="#90CAF9" p-id="1767"></path><path d="M986.112 58.368l-21.504 376.32-313.856 44.544L665.6 87.04z" fill="#2196F3" p-id="1768"></path><path d="M220.16 1020.416l-168.96-112.64 1.536-370.176 173.056 91.648z" fill="#64B5F6" p-id="1769"></path><path d="M225.792 629.248L52.736 537.6l335.872-46.592 185.344 84.48z" fill="#1976D2" p-id="1770"></path><path d="M573.952 575.488l-12.8 375.296L220.16 1020.416l5.632-391.168z" fill="#2196F3" p-id="1771"></path><path d="M504.832 413.184L319.488 336.896l4.096-210.432 187.904 64.512z" fill="#FF8F00" p-id="1772"></path><path d="M309.248 438.784L131.072 358.912l188.416-22.016 185.344 76.288z" fill="#C16500" p-id="1773"></path><path d="M226.816 539.648L53.248 453.12l1.536-390.144 178.176 62.976z" fill="#FFD366" p-id="1774"></path><path d="M232.96 125.952L54.784 62.976 399.36 35.328l191.488 58.368z" fill="#FFE5AB" p-id="1775"></path><path d="M232.96 125.952l357.888-31.744-13.824 395.776-350.208 49.664 6.144-413.696z m271.872 287.232l6.656-222.208-197.632 19.968-4.096 227.84 195.072-25.6" fill="#FFC107" p-id="1776"></path></svg>
|
||||
|
After Width: | Height: | Size: 2.0 KiB |
@@ -5,7 +5,6 @@
|
||||
gap: 20px;
|
||||
justify-items: center;
|
||||
min-height: 100px;
|
||||
margin-top: 40px;
|
||||
|
||||
.item {
|
||||
overflow: hidden;
|
||||
|
||||
@@ -5,6 +5,7 @@ import { getLinkListAPI, addLinkDataAPI, editLinkDataAPI, delLinkDataAPI, getWeb
|
||||
import { WebType, Web } from '@/types/app/web';
|
||||
import Title from '@/components/Title';
|
||||
import { RuleObject } from 'antd/es/form';
|
||||
import group from "./assets/svg/group.svg"
|
||||
import './index.scss';
|
||||
|
||||
export default () => {
|
||||
@@ -15,7 +16,7 @@ export default () => {
|
||||
const [form] = Form.useForm();
|
||||
|
||||
const [tab, setTab] = useState<string>('list');
|
||||
const [list, setList] = useState<Web[]>([]);
|
||||
const [list, setList] = useState<{ [key: string]: Web[] }>({});
|
||||
const [listTemp, setListTemp] = useState<Web[]>([]);
|
||||
const [typeList, setTypeList] = useState<WebType[]>([]);
|
||||
const [search, setSearch] = useState<string>('');
|
||||
@@ -27,17 +28,27 @@ export default () => {
|
||||
// 获取网站列表
|
||||
const getLinkList = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
|
||||
const { data } = await getLinkListAPI();
|
||||
data.sort((a, b) => a.order - b.order)
|
||||
data.sort((a, b) => a.type.order - b.type.order)
|
||||
|
||||
setList(data);
|
||||
const grouped = data.reduce((acc, item) => {
|
||||
const groupName = item.type.name;
|
||||
if (!acc[groupName]) {
|
||||
acc[groupName] = [];
|
||||
}
|
||||
acc[groupName].push(item);
|
||||
return acc;
|
||||
}, {} as { [key: string]: Web[] });
|
||||
|
||||
setList(grouped);
|
||||
setListTemp(data);
|
||||
setLoading(false)
|
||||
} catch (error) {
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
setLoading(false)
|
||||
};
|
||||
|
||||
// 获取网站类型列表
|
||||
@@ -47,19 +58,33 @@ export default () => {
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setLoading(true);
|
||||
getLinkList();
|
||||
getWebTypeList();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
setListTemp(list.filter(item => item.title.includes(search) || item.description.includes(search)));
|
||||
}, [search, list]);
|
||||
// 过滤出符合搜索条件的网站
|
||||
const filteredList = listTemp.filter(item =>
|
||||
item.title.includes(search) || item.description.includes(search)
|
||||
);
|
||||
|
||||
// 按类型分组
|
||||
const grouped = filteredList.reduce((acc, item) => {
|
||||
const groupName = item.type.name;
|
||||
if (!acc[groupName]) {
|
||||
acc[groupName] = [];
|
||||
}
|
||||
acc[groupName].push(item);
|
||||
return acc;
|
||||
}, {} as { [key: string]: Web[] });
|
||||
|
||||
setList(grouped);
|
||||
}, [search, listTemp]);
|
||||
|
||||
const deleteLinkData = async (id: number) => {
|
||||
setLoading(true);
|
||||
|
||||
try {
|
||||
setLoading(true);
|
||||
|
||||
await delLinkDataAPI(id);
|
||||
await getLinkList();
|
||||
message.success('🎉 删除网站成功');
|
||||
@@ -69,20 +94,19 @@ export default () => {
|
||||
};
|
||||
|
||||
const editLinkData = async (record: Web) => {
|
||||
setEditLoading(true)
|
||||
|
||||
try {
|
||||
setEditLoading(true)
|
||||
setTab('operate');
|
||||
setIsMethod("edit");
|
||||
|
||||
const { data } = await getLinkDataAPI(record.id)
|
||||
setLink(data);
|
||||
|
||||
form.setFieldsValue(data);
|
||||
setEditLoading(false)
|
||||
} catch (error) {
|
||||
setEditLoading(false)
|
||||
}
|
||||
|
||||
setEditLoading(false)
|
||||
};
|
||||
|
||||
// 做一些初始化的事情
|
||||
@@ -98,9 +122,9 @@ export default () => {
|
||||
};
|
||||
|
||||
const submit = async () => {
|
||||
setBtnLoading(true)
|
||||
|
||||
try {
|
||||
setBtnLoading(true)
|
||||
|
||||
form.validateFields().then(async (values: Web) => {
|
||||
if (isMethod === "edit") {
|
||||
await editLinkDataAPI({ ...link, ...values });
|
||||
@@ -114,11 +138,11 @@ export default () => {
|
||||
reset()
|
||||
setTab('list');
|
||||
});
|
||||
|
||||
setBtnLoading(false)
|
||||
} catch (error) {
|
||||
setBtnLoading(false)
|
||||
}
|
||||
|
||||
setBtnLoading(false)
|
||||
};
|
||||
|
||||
const { Option } = Select;
|
||||
@@ -137,56 +161,70 @@ export default () => {
|
||||
label: '网站列表',
|
||||
key: 'list',
|
||||
children: (
|
||||
<>
|
||||
<div className="w-[300px] mx-auto">
|
||||
<div>
|
||||
<div className="flex justify-end w-full mb-8">
|
||||
<Input
|
||||
size="large"
|
||||
placeholder="请输入网站名称或描述信息进行查询"
|
||||
prefix={<SearchOutlined />}
|
||||
value={search}
|
||||
onChange={e => setSearch(e.target.value)}
|
||||
className='w-[400px]'
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Spin spinning={loading}>
|
||||
{listTemp.length > 0 ? (
|
||||
<div className="list">
|
||||
{
|
||||
listTemp.map(item => (
|
||||
<div key={item.id} className="item">
|
||||
<div className="avatar">
|
||||
<img src={item.image} alt="" className="avatar-img" />
|
||||
</div>
|
||||
<div className='space-y-8'>
|
||||
{
|
||||
Object.keys(list).map((key) => (
|
||||
<div>
|
||||
<Card className="[&>.ant-card-body]:flex [&>.ant-card-body]:py-2 [&>.ant-card-body]:px-4 my-2 ml-1.5 text-base bg-[#f5f6ff] dark:bg-boxdark transition-colors">
|
||||
<img src={group} alt="分组图标" className='w-6 h-6 mr-2' />
|
||||
<span>{key}</span>
|
||||
</Card>
|
||||
|
||||
<div className="name">{item.title}</div>
|
||||
<div className="description">{item.description}</div>
|
||||
<div className="type">{item.type.name}</div>
|
||||
{
|
||||
Object.values(list[key]).length ? (
|
||||
<div className="list">
|
||||
{
|
||||
Object.values(list[key]).map(item => (
|
||||
<div key={item.id} className="item">
|
||||
<div className="avatar">
|
||||
<img src={item.image} alt="" className="avatar-img" />
|
||||
</div>
|
||||
|
||||
<div className="operate">
|
||||
<div onClick={() => editLinkData(item)} className="edit">修改</div>
|
||||
<div className="name">{item.title}</div>
|
||||
<div className="description">{item.description}</div>
|
||||
<div className="type">{item.type.name}</div>
|
||||
|
||||
<Popconfirm title="警告" description="你确定要删除吗" okText="确定" cancelText="取消" onConfirm={() => deleteLinkData(item.id!)}>
|
||||
<div className="delete">删除</div>
|
||||
</Popconfirm>
|
||||
</div>
|
||||
<div className="operate">
|
||||
<div onClick={() => editLinkData(item)} className="edit">修改</div>
|
||||
|
||||
<div onClick={() => toHref(item.url)} className="headFor">前往该网站 →</div>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
) : (
|
||||
<Empty description="暂无数据" className='my-7' />
|
||||
)}
|
||||
<Popconfirm title="警告" description="你确定要删除吗" okText="确定" cancelText="取消" onConfirm={() => deleteLinkData(item.id!)}>
|
||||
<div className="delete">删除</div>
|
||||
</Popconfirm>
|
||||
</div>
|
||||
|
||||
<div onClick={() => toHref(item.url)} className="headFor">前往该网站 →</div>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
) : <Empty description="暂无数据" className='my-7' />
|
||||
}
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</Spin>
|
||||
</>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
label: isMethod === "edit" ? '编辑网站' : '新增网站',
|
||||
key: 'operate',
|
||||
children: (
|
||||
<>
|
||||
<div>
|
||||
<h2 className="text-xl pb-4 text-center">{isMethod === "edit" ? '编辑网站' : '新增网站'}</h2>
|
||||
|
||||
<Spin spinning={editLoading}>
|
||||
@@ -232,7 +270,7 @@ export default () => {
|
||||
</Form>
|
||||
</div>
|
||||
</Spin>
|
||||
</>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
@@ -27,6 +27,8 @@ export default () => {
|
||||
// 重新获取最新数据
|
||||
const fetchData = async (type: Menu) => {
|
||||
try {
|
||||
setLoading(true)
|
||||
|
||||
if (type === "comment") {
|
||||
const { data } = await getCommentListAPI({ query: { status: 0 }, pattern: "list" });
|
||||
setCommentList(data);
|
||||
@@ -37,15 +39,14 @@ export default () => {
|
||||
const { data } = await getWallListAPI({ query: { status: 0 } });
|
||||
setWallList(data);
|
||||
}
|
||||
|
||||
setLoading(false)
|
||||
} catch (error) {
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
setLoading(false)
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setLoading(true)
|
||||
fetchData(active);
|
||||
}, [active]);
|
||||
|
||||
|
||||
@@ -7,4 +7,44 @@
|
||||
padding: 8px 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------> Antd组件库暗色适配 开始 <------------------
|
||||
.ant-card {
|
||||
@apply overflow-hidden;
|
||||
}
|
||||
|
||||
.ant-card-body,
|
||||
.ant-pagination-item,
|
||||
.ant-drawer-header,
|
||||
.ant-drawer-body,
|
||||
.ant-table-cell::before {
|
||||
@apply dark:bg-boxdark;
|
||||
}
|
||||
|
||||
.ant-pagination-item:hover,
|
||||
.ant-table-cell,
|
||||
.ant-table-row:hover .ant-table-cell,
|
||||
.ant-card {
|
||||
@apply dark:!bg-boxdark dark:!border-strokedark;
|
||||
}
|
||||
|
||||
.ant-input,
|
||||
.ant-input-affix-wrapper,
|
||||
.ant-picker-outlined,
|
||||
.ant-picker-panel-layout,
|
||||
.ant-picker-range-arrow::before,
|
||||
.ant-select,
|
||||
.ant-select-selector,
|
||||
.ant-modal-content {
|
||||
@apply dark:!bg-boxdark-2 dark:!border-strokedark;
|
||||
}
|
||||
|
||||
.ant-modal-header{
|
||||
@apply dark:bg-transparent;
|
||||
}
|
||||
|
||||
.ant-transfer-list{
|
||||
@apply dark:border-strokedark;
|
||||
}
|
||||
// ------------------> Antd组件库暗色适配 结束 <------------------
|
||||
2
src/types/env.d.ts
vendored
2
src/types/env.d.ts
vendored
@@ -6,7 +6,7 @@ interface ImportMetaEnv {
|
||||
readonly VITE_BAIDU_TONGJI_SITE_ID: string;
|
||||
readonly VITE_BAIDU_TONGJI_ACCESS_TOKEN: string;
|
||||
|
||||
readonly VITE_AI_APIPassword: string;
|
||||
readonly VITE_AI_APIPASSWORD: string;
|
||||
readonly VITE_AI_MODEL: string;
|
||||
|
||||
readonly VITE_GAODE_WEB_API: string;
|
||||
|
||||
@@ -40,7 +40,7 @@ module.exports = {
|
||||
whiten: '#F1F5F9',
|
||||
whiter: '#F5F7FD',
|
||||
boxdark: '#334459',
|
||||
'boxdark-2': '#1A222C',
|
||||
'boxdark-2': '#263444',
|
||||
strokedark: '#475f7d',
|
||||
'form-strokedark': '#3d4d60',
|
||||
'form-input': '#1d2a39',
|
||||
|
||||
@@ -26,7 +26,7 @@ export default defineConfig({
|
||||
'/baidu': {
|
||||
target: 'https://openapi.baidu.com/',
|
||||
changeOrigin: true,
|
||||
rewrite: (path) => path.replace(/^\/api/, ''),
|
||||
rewrite: (path) => path.replace(/^\/baidu/, ''),
|
||||
},
|
||||
'/qiniu': {
|
||||
target: 'https://rsf.qiniuapi.com/',
|
||||
|
||||
Reference in New Issue
Block a user