(null);
+ const handleEditCookie = (cookie: Cookie) => () => {
+ setEditCookie(cookie);
+ setShowEditModal(true);
+ };
+
+ let data = [];
+ if (siteName) {
+ data = cookiesList.filter((tSite) => tSite.site_name === siteName);
+ }
+
+ const columns: TableColumnProps[] = [
+ {
+ title: 'ID',
+ dataIndex: 'id',
+ },
+ {
+ title: 'Cookie 名称',
+ dataIndex: 'cookie_name',
+ },
+ {
+ title: '所属站点',
+ dataIndex: 'site_name',
+ },
+ {
+ title: '最后使用时间',
+ dataIndex: 'last_usage',
+ },
+ {
+ title: '状态',
+ dataIndex: 'status',
+ },
+ {
+ title: 'CD',
+ dataIndex: 'cd_milliseconds',
+ }, {
+ title: '操作',
+ dataIndex: 'op',
+ render: (_: null, record: Cookie) => (
+
+
+
+ {/* */}
+
+
+
+
+
+ ),
+
+ },
+
+ ];
+
+ return (
+ <>
+
+
+ Cookie 管理
+
+
+
+
+
+
+
+ >
+ );
+}
diff --git a/admin-frontend/src/features/cookieManager/cookieConfigSlice.ts b/admin-frontend/src/features/cookieManager/cookieConfigSlice.ts
new file mode 100644
index 0000000..497b270
--- /dev/null
+++ b/admin-frontend/src/features/cookieManager/cookieConfigSlice.ts
@@ -0,0 +1,66 @@
+import { createApi } from '@reduxjs/toolkit/query/react';
+import {
+ StatusResp, Cookie, NewCookieParam,
+ DelCookieParam, CookieTarget, NewCookieTargetParam, DelCookieTargetParam,
+} from '../../utils/type';
+import { baseQueryWithAuth } from '../auth/authQuery';
+
+export const cookieApi = createApi({
+ reducerPath: 'cookie',
+ baseQuery: baseQueryWithAuth,
+ tagTypes: ['Cookie'],
+ endpoints: (builder) => ({
+ getCookies: builder.query({
+ query: () => '/cookie',
+ providesTags: ['Cookie'],
+ }),
+ newCookie: builder.mutation({
+ query: ({ siteName, content }) => ({
+ method: 'POST',
+ url: `/cookie?site_name=${siteName}&content=${content}`,
+ }),
+ invalidatesTags: ['Cookie'],
+ }),
+ deleteCookie: builder.mutation({
+ query: ({ cookieId }) => ({
+ method: 'DELETE',
+ url: `/cookie/${cookieId}`,
+ }),
+ invalidatesTags: ['Cookie'],
+ }),
+ }),
+});
+
+export const {
+ useGetCookiesQuery, useNewCookieMutation, useDeleteCookieMutation,
+} = cookieApi;
+
+export const cookieTargetApi = createApi({
+ reducerPath: 'cookieTarget',
+ baseQuery: baseQueryWithAuth,
+ tagTypes: ['CookieTarget'],
+ endpoints: (builder) => ({
+ getCookieTargets: builder.query({
+ query: ({ cookieId }) => `/cookie_target?cookie_id=${cookieId}`,
+ providesTags: ['CookieTarget'],
+ }),
+ newCookieTarget: builder.mutation({
+ query: ({ platformName, target, cookieId }) => ({
+ method: 'POST',
+ url: `/cookie_target?platform_name=${platformName}&target=${encodeURIComponent(target)}&cookie_id=${cookieId}`,
+ }),
+ invalidatesTags: ['CookieTarget'],
+ }),
+ deleteCookieTarget: builder.mutation({
+ query: ({ platformName, target, cookieId }) => ({
+ method: 'DELETE',
+ url: `/cookie_target?platform_name=${platformName}&target=${encodeURIComponent(target)}&cookie_id=${cookieId}`,
+ }),
+ invalidatesTags: ['CookieTarget'],
+ }),
+ }),
+});
+
+export const {
+ useGetCookieTargetsQuery, useNewCookieTargetMutation, useDeleteCookieTargetMutation,
+} = cookieTargetApi;
diff --git a/admin-frontend/src/features/cookieManager/cookieValidateReq.ts b/admin-frontend/src/features/cookieManager/cookieValidateReq.ts
new file mode 100644
index 0000000..6e8e5cb
--- /dev/null
+++ b/admin-frontend/src/features/cookieManager/cookieValidateReq.ts
@@ -0,0 +1,20 @@
+import { AppThunk } from '../../app/store';
+import { baseUrl } from '../../utils/urls';
+
+// eslint-disable-next-line
+export const validCookie =
+ (siteName: string, content: string): AppThunk> => async (_, getState) => {
+ const url = `${baseUrl}cookie/validate?site_name=${siteName}&content=${content}`;
+ const state = getState();
+ const authToken = state.auth.token;
+ const res = await fetch(url, {
+ headers: {
+ Authorization: `Bearer ${authToken}`,
+ },
+ method: 'POST',
+ });
+ const resObj = await res.json();
+ return resObj.ok;
+ };
+
+export default validCookie;
diff --git a/admin-frontend/src/features/cookieTargetManager/CookieTargetModal.tsx b/admin-frontend/src/features/cookieTargetManager/CookieTargetModal.tsx
new file mode 100644
index 0000000..550b921
--- /dev/null
+++ b/admin-frontend/src/features/cookieTargetManager/CookieTargetModal.tsx
@@ -0,0 +1,109 @@
+import React
+ from 'react';
+import {
+ Empty, Form, Modal, Select,
+} from '@arco-design/web-react';
+import { Cookie, SubscribeConfig, SubscribeGroupDetail } from '../../utils/type';
+import { useNewCookieTargetMutation } from '../cookieManager/cookieConfigSlice';
+import { useGetSubsQuery } from '../subsribeConfigManager/subscribeConfigSlice';
+import { useAppSelector } from '../../app/hooks';
+import { selectPlatformConf } from '../globalConf/globalConfSlice';
+
+interface SubscribeModalProp {
+ cookie:Cookie| null
+ visible: boolean;
+ setVisible: (arg0: boolean) => void;
+}
+
+export default function CookieTargetModal({
+ cookie, visible, setVisible,
+}: SubscribeModalProp) {
+ if (!cookie) {
+ return ;
+ }
+ const [newCookieTarget] = useNewCookieTargetMutation();
+ const FormItem = Form.Item;
+
+ // 筛选出当前Cookie支持的平台
+ const platformConf = useAppSelector(selectPlatformConf);
+ const platformThatSiteSupport = Object.values(platformConf).reduce((p, c) => {
+ if (c.siteName in p) {
+ p[c.siteName].push(c.platformName);
+ } else {
+ p[c.siteName] = [c.platformName];
+ }
+ return p;
+ }, {} as Record);
+ const supportedPlatform = platformThatSiteSupport[cookie.site_name];
+
+ const { data: subs } = useGetSubsQuery();
+ const pureSubs:SubscribeConfig[] = subs ? Object.values(subs)
+ .reduce((
+ pv:Array,
+ cv:SubscribeGroupDetail,
+ ) => pv.concat(cv.subscribes), []) : [];
+ const filteredSubs = pureSubs.filter((sub) => supportedPlatform.includes(sub.platformName));
+ const [index, setIndex] = React.useState(-1);
+
+ const handleSubmit = (idx:number) => {
+ const postPromise: ReturnType = newCookieTarget({
+ cookieId: cookie.id,
+ platformName: filteredSubs[idx].platformName,
+ target: filteredSubs[idx].target,
+ });
+ postPromise.then(() => {
+ setVisible(false);
+ });
+ };
+ const { Option } = Select;
+
+ return (
+ setVisible(false)}
+ onOk={() => handleSubmit(index)}
+ >
+
+
+
+ );
+}
diff --git a/admin-frontend/src/features/globalConf/globalConfSlice.ts b/admin-frontend/src/features/globalConf/globalConfSlice.ts
index 8c653f6..a9f0d8e 100644
--- a/admin-frontend/src/features/globalConf/globalConfSlice.ts
+++ b/admin-frontend/src/features/globalConf/globalConfSlice.ts
@@ -6,6 +6,7 @@ import { globalConfUrl } from '../../utils/urls';
const initialState = {
loaded: false,
platformConf: {},
+ siteConf: {},
} as GlobalConf;
export const loadGlobalConf = createAsyncThunk(
@@ -24,6 +25,7 @@ export const globalConfSlice = createSlice({
builder
.addCase(loadGlobalConf.fulfilled, (state, payload) => {
state.platformConf = payload.payload.platformConf;
+ state.siteConf = payload.payload.siteConf;
state.loaded = true;
});
},
@@ -33,3 +35,4 @@ export default globalConfSlice.reducer;
export const selectGlobalConfLoaded = (state: RootState) => state.globalConf.loaded;
export const selectPlatformConf = (state: RootState) => state.globalConf.platformConf;
+export const selectSiteConf = (state: RootState) => state.globalConf.siteConf;
diff --git a/admin-frontend/src/pages/Home.tsx b/admin-frontend/src/pages/Home.tsx
index 2c676b4..cc5eb9b 100644
--- a/admin-frontend/src/pages/Home.tsx
+++ b/admin-frontend/src/pages/Home.tsx
@@ -1,13 +1,15 @@
import React, { ReactNode, useEffect, useState } from 'react';
import { Breadcrumb, Layout, Menu } from '@arco-design/web-react';
-import { IconRobot, IconDashboard } from '@arco-design/web-react/icon';
+import {
+ IconRobot, IconDashboard, IconIdcard,
+} from '@arco-design/web-react/icon';
import './Home.css';
-// import SubscribeManager from '../features/subsribeConfigManager/SubscribeManager';
import {
Link, Navigate, Outlet, useLocation, useNavigate,
} from 'react-router-dom';
import { useAppSelector } from '../app/hooks';
import { selectIsLogin } from '../features/auth/authSlice';
+import { selectSiteConf } from '../features/globalConf/globalConfSlice';
export default function Home() {
const location = useLocation();
@@ -23,6 +25,12 @@ export default function Home() {
if (path !== '/home/groups' && !path.startsWith('/home/groups/') && path !== '/home/weight') {
navigate('/home/groups');
}
+ if (path === '/home/cookie') {
+ navigate('/home/cookie');
+ }
+ if (path.startsWith('/home/cookie/')) {
+ navigate(path);
+ }
}, [path]);
let currentKey = '';
@@ -30,6 +38,8 @@ export default function Home() {
currentKey = 'groups';
} else if (path.startsWith('/home/groups/')) {
currentKey = 'subs';
+ } else if (path.startsWith('/home/cookie/')) {
+ currentKey = path.substring(6);
}
const [selectedTab, changeSelectTab] = useState(currentKey);
@@ -40,6 +50,10 @@ export default function Home() {
navigate('/home/groups');
} else if (tab === 'weight') {
navigate('/home/weight');
+ } else if (tab === 'cookie') {
+ navigate('/home/cookie');
+ } else if (tab.startsWith('cookie/')) {
+ navigate(`/home/${tab}`);
}
};
@@ -80,7 +94,22 @@ export default function Home() {
);
+ } else if (path.startsWith('/home/cookie')) {
+ breadcrumbContent = (
+
+
+
+
+ Cookie 管理
+
+
+
+ );
}
+ const MenuItem = Menu.Item;
+ const { SubMenu } = Menu;
+ const siteConf = useAppSelector(selectSiteConf);
+
return (
@@ -95,12 +124,29 @@ export default function Home() {
>