feat: 实现Operation-Agent核心功能及电商平台适配器
refactor: 重构项目结构,分离server和dashboard代码 style: 统一代码风格,修复lint警告 test: 添加平台适配器工厂测试用例 ci: 更新CI/CD流程,增加语义验证和性能测试 docs: 添加语义中心文档,定义统一数据模型和状态机
This commit is contained in:
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
14
dashboard/src/App.tsx
Normal file
14
dashboard/src/App.tsx
Normal file
@@ -0,0 +1,14 @@
|
||||
import React from 'react';
|
||||
import { ConfigProvider } from 'antd';
|
||||
import zhCN from 'antd/lib/locale/zh_CN';
|
||||
import AppRouter from './router';
|
||||
|
||||
const App: React.FC = () => {
|
||||
return (
|
||||
<ConfigProvider locale={zhCN}>
|
||||
<AppRouter />
|
||||
</ConfigProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
||||
445
dashboard/src/pages/OperationAgent.tsx
Normal file
445
dashboard/src/pages/OperationAgent.tsx
Normal file
@@ -0,0 +1,445 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Button, Table, Form, Input, Select, Modal, message, Card, Tabs, Space, Tag, Divider, Alert } from 'antd';
|
||||
import { PlusOutlined, SyncOutlined, EditOutlined, DeleteOutlined, CheckOutlined, CloseOutlined, LoadingOutlined } from '@ant-design/icons';
|
||||
import { operationAgentService, Store, StoreBindingData } from '../services/operationAgentService';
|
||||
|
||||
const { Option } = Select;
|
||||
const { TabPane } = Tabs;
|
||||
const { TextArea } = Input;
|
||||
|
||||
const platforms = [
|
||||
{ value: 'amazon', label: 'Amazon' },
|
||||
{ value: 'shopee', label: 'Shopee' },
|
||||
{ value: 'aliexpress', label: 'AliExpress' },
|
||||
{ value: 'tiktok', label: 'TikTok' },
|
||||
{ value: 'ebay', label: 'Ebay' },
|
||||
{ value: 'lazada', label: 'Lazada' },
|
||||
{ value: 'wish', label: 'Wish' },
|
||||
{ value: 'shein', label: 'Shein' },
|
||||
{ value: 'jd_worldwide', label: 'JD Worldwide' },
|
||||
{ value: 'walmart', label: 'Walmart' },
|
||||
{ value: 'etsy', label: 'Etsy' },
|
||||
{ value: 'target', label: 'Target' },
|
||||
{ value: 'newegg', label: 'Newegg' },
|
||||
{ value: 'cdiscount', label: 'Cdiscount' },
|
||||
{ value: 'allegro', label: 'Allegro' },
|
||||
{ value: 'otto', label: 'Otto' },
|
||||
{ value: 'rakuten', label: 'Rakuten' },
|
||||
{ value: 'qoo10', label: 'Qoo10' },
|
||||
];
|
||||
|
||||
const statusMap = {
|
||||
active: { color: 'green', text: '活跃' },
|
||||
inactive: { color: 'red', text: '停用' },
|
||||
pending: { color: 'orange', text: '待处理' },
|
||||
suspended: { color: 'gray', text: '暂停' },
|
||||
};
|
||||
|
||||
const OperationAgent: React.FC = () => {
|
||||
const [stores, setStores] = useState<Store[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [bindingModalVisible, setBindingModalVisible] = useState(false);
|
||||
const [currentStore, setCurrentStore] = useState<Store | null>(null);
|
||||
const [merchantId, setMerchantId] = useState('merchant-1'); // 默认商户ID
|
||||
const [form] = Form.useForm();
|
||||
|
||||
// 加载店铺列表
|
||||
const loadStores = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const data = await operationAgentService.getStores(merchantId);
|
||||
setStores(data);
|
||||
} catch (error) {
|
||||
message.error('加载店铺失败');
|
||||
console.error(error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 初始加载
|
||||
useEffect(() => {
|
||||
loadStores();
|
||||
}, [merchantId]);
|
||||
|
||||
// 绑定店铺
|
||||
const handleBindStore = async (values: any) => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const bindingData: StoreBindingData = {
|
||||
merchantId: values.merchantId,
|
||||
platform: values.platform,
|
||||
platformShopId: values.platformShopId,
|
||||
name: values.name,
|
||||
description: values.description,
|
||||
authInfo: {
|
||||
...(values.platform === 'amazon' && {
|
||||
accessKey: values.accessKey,
|
||||
secretKey: values.secretKey,
|
||||
sellerId: values.sellerId,
|
||||
marketplaceId: values.marketplaceId,
|
||||
}),
|
||||
...(values.platform === 'shopee' && {
|
||||
partnerId: values.partnerId,
|
||||
partnerKey: values.partnerKey,
|
||||
shopId: values.shopId,
|
||||
}),
|
||||
...(values.platform === 'aliexpress' && {
|
||||
appKey: values.appKey,
|
||||
appSecret: values.appSecret,
|
||||
accessToken: values.accessToken,
|
||||
}),
|
||||
...(values.platform === 'tiktok' && {
|
||||
appId: values.appId,
|
||||
appSecret: values.appSecret,
|
||||
accessToken: values.accessToken,
|
||||
}),
|
||||
...(values.platform === 'ebay' && {
|
||||
clientId: values.clientId,
|
||||
clientSecret: values.clientSecret,
|
||||
refreshToken: values.refreshToken,
|
||||
}),
|
||||
...(values.platform && !['amazon', 'shopee', 'aliexpress', 'tiktok', 'ebay'].includes(values.platform) && {
|
||||
apiKey: values.apiKey,
|
||||
apiSecret: values.apiSecret,
|
||||
}),
|
||||
},
|
||||
};
|
||||
|
||||
await operationAgentService.bindStore(bindingData);
|
||||
message.success('店铺绑定成功');
|
||||
setBindingModalVisible(false);
|
||||
form.resetFields();
|
||||
loadStores();
|
||||
} catch (error) {
|
||||
message.error('店铺绑定失败');
|
||||
console.error(error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 同步商品
|
||||
const handleSyncProducts = async (storeId: string) => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const result = await operationAgentService.syncProducts(storeId);
|
||||
if (result.success) {
|
||||
message.success(`商品同步成功,共 ${result.count} 个商品`);
|
||||
} else {
|
||||
message.error('商品同步失败');
|
||||
}
|
||||
} catch (error) {
|
||||
message.error('商品同步失败');
|
||||
console.error(error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 同步订单
|
||||
const handleSyncOrders = async (storeId: string) => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const result = await operationAgentService.syncOrders(storeId);
|
||||
if (result.success) {
|
||||
message.success(`订单同步成功,共 ${result.count} 个订单`);
|
||||
} else {
|
||||
message.error('订单同步失败');
|
||||
}
|
||||
} catch (error) {
|
||||
message.error('订单同步失败');
|
||||
console.error(error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 停用店铺
|
||||
const handleDeactivateStore = async (storeId: string) => {
|
||||
setLoading(true);
|
||||
try {
|
||||
await operationAgentService.deactivateStore(storeId);
|
||||
message.success('店铺已停用');
|
||||
loadStores();
|
||||
} catch (error) {
|
||||
message.error('停用店铺失败');
|
||||
console.error(error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 重新激活店铺
|
||||
const handleReactivateStore = async (storeId: string) => {
|
||||
setLoading(true);
|
||||
try {
|
||||
await operationAgentService.reactivateStore(storeId);
|
||||
message.success('店铺已重新激活');
|
||||
loadStores();
|
||||
} catch (error) {
|
||||
message.error('激活店铺失败');
|
||||
console.error(error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 查看店铺详情
|
||||
const handleViewStore = async (storeId: string) => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const store = await operationAgentService.getStore(storeId);
|
||||
setCurrentStore(store);
|
||||
} catch (error) {
|
||||
message.error('获取店铺详情失败');
|
||||
console.error(error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 渲染平台特定的授权信息表单
|
||||
const renderAuthInfoForm = (platform: string) => {
|
||||
switch (platform) {
|
||||
case 'amazon':
|
||||
return (
|
||||
<>
|
||||
<Form.Item name="accessKey" label="Access Key" rules={[{ required: true, message: '请输入Access Key' }]}>
|
||||
<Input placeholder="请输入Access Key" />
|
||||
</Form.Item>
|
||||
<Form.Item name="secretKey" label="Secret Key" rules={[{ required: true, message: '请输入Secret Key' }]}>
|
||||
<Input.Password placeholder="请输入Secret Key" />
|
||||
</Form.Item>
|
||||
<Form.Item name="sellerId" label="Seller ID" rules={[{ required: true, message: '请输入Seller ID' }]}>
|
||||
<Input placeholder="请输入Seller ID" />
|
||||
</Form.Item>
|
||||
<Form.Item name="marketplaceId" label="Marketplace ID" rules={[{ required: true, message: '请输入Marketplace ID' }]}>
|
||||
<Input placeholder="请输入Marketplace ID" />
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
case 'shopee':
|
||||
return (
|
||||
<>
|
||||
<Form.Item name="partnerId" label="Partner ID" rules={[{ required: true, message: '请输入Partner ID' }]}>
|
||||
<Input placeholder="请输入Partner ID" />
|
||||
</Form.Item>
|
||||
<Form.Item name="partnerKey" label="Partner Key" rules={[{ required: true, message: '请输入Partner Key' }]}>
|
||||
<Input.Password placeholder="请输入Partner Key" />
|
||||
</Form.Item>
|
||||
<Form.Item name="shopId" label="Shop ID" rules={[{ required: true, message: '请输入Shop ID' }]}>
|
||||
<Input placeholder="请输入Shop ID" />
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
case 'aliexpress':
|
||||
return (
|
||||
<>
|
||||
<Form.Item name="appKey" label="App Key" rules={[{ required: true, message: '请输入App Key' }]}>
|
||||
<Input placeholder="请输入App Key" />
|
||||
</Form.Item>
|
||||
<Form.Item name="appSecret" label="App Secret" rules={[{ required: true, message: '请输入App Secret' }]}>
|
||||
<Input.Password placeholder="请输入App Secret" />
|
||||
</Form.Item>
|
||||
<Form.Item name="accessToken" label="Access Token" rules={[{ required: true, message: '请输入Access Token' }]}>
|
||||
<Input placeholder="请输入Access Token" />
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
case 'tiktok':
|
||||
return (
|
||||
<>
|
||||
<Form.Item name="appId" label="App ID" rules={[{ required: true, message: '请输入App ID' }]}>
|
||||
<Input placeholder="请输入App ID" />
|
||||
</Form.Item>
|
||||
<Form.Item name="appSecret" label="App Secret" rules={[{ required: true, message: '请输入App Secret' }]}>
|
||||
<Input.Password placeholder="请输入App Secret" />
|
||||
</Form.Item>
|
||||
<Form.Item name="accessToken" label="Access Token" rules={[{ required: true, message: '请输入Access Token' }]}>
|
||||
<Input placeholder="请输入Access Token" />
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
case 'ebay':
|
||||
return (
|
||||
<>
|
||||
<Form.Item name="clientId" label="Client ID" rules={[{ required: true, message: '请输入Client ID' }]}>
|
||||
<Input placeholder="请输入Client ID" />
|
||||
</Form.Item>
|
||||
<Form.Item name="clientSecret" label="Client Secret" rules={[{ required: true, message: '请输入Client Secret' }]}>
|
||||
<Input.Password placeholder="请输入Client Secret" />
|
||||
</Form.Item>
|
||||
<Form.Item name="refreshToken" label="Refresh Token" rules={[{ required: true, message: '请输入Refresh Token' }]}>
|
||||
<Input placeholder="请输入Refresh Token" />
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
default:
|
||||
return (
|
||||
<>
|
||||
<Form.Item name="apiKey" label="API Key" rules={[{ required: true, message: '请输入API Key' }]}>
|
||||
<Input placeholder="请输入API Key" />
|
||||
</Form.Item>
|
||||
<Form.Item name="apiSecret" label="API Secret" rules={[{ required: true, message: '请输入API Secret' }]}>
|
||||
<Input.Password placeholder="请输入API Secret" />
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ padding: '20px' }}>
|
||||
<Card title="Operation-Agent 管理" extra={<Button type="primary" icon={<PlusOutlined />} onClick={() => setBindingModalVisible(true)}>绑定店铺</Button>}>
|
||||
<Alert
|
||||
message="操作说明"
|
||||
description="本页面用于管理Operation-Agent平台集成,包括店铺绑定、商品/订单同步等功能。"
|
||||
type="info"
|
||||
style={{ marginBottom: '20px' }}
|
||||
/>
|
||||
|
||||
<Form layout="inline" onFinish={(values) => setMerchantId(values.merchantId)} style={{ marginBottom: '20px' }}>
|
||||
<Form.Item name="merchantId" initialValue={merchantId} label="商户ID">
|
||||
<Input placeholder="请输入商户ID" />
|
||||
</Form.Item>
|
||||
<Form.Item>
|
||||
<Button type="primary" htmlType="submit">查询</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
|
||||
<Table
|
||||
loading={loading}
|
||||
dataSource={stores}
|
||||
rowKey="id"
|
||||
columns={[
|
||||
{
|
||||
title: '店铺名称',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
},
|
||||
{
|
||||
title: '平台',
|
||||
dataIndex: 'platform',
|
||||
key: 'platform',
|
||||
render: (platform: string) => {
|
||||
const platformInfo = platforms.find(p => p.value === platform);
|
||||
return platformInfo ? platformInfo.label : platform;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '平台店铺ID',
|
||||
dataIndex: 'platformShopId',
|
||||
key: 'platformShopId',
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
key: 'status',
|
||||
render: (status: string) => {
|
||||
const statusInfo = statusMap[status as keyof typeof statusMap];
|
||||
return statusInfo ? (
|
||||
<Tag color={statusInfo.color}>{statusInfo.text}</Tag>
|
||||
) : (
|
||||
<Tag color="default">{status}</Tag>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: 'created_at',
|
||||
key: 'created_at',
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
render: (_: any, record: Store) => (
|
||||
<Space size="middle">
|
||||
<Button icon={<SyncOutlined />} onClick={() => handleSyncProducts(record.id)}>同步商品</Button>
|
||||
<Button icon={<SyncOutlined />} onClick={() => handleSyncOrders(record.id)}>同步订单</Button>
|
||||
{record.status === 'active' ? (
|
||||
<Button danger icon={<CloseOutlined />} onClick={() => handleDeactivateStore(record.id)}>停用</Button>
|
||||
) : (
|
||||
<Button type="primary" icon={<CheckOutlined />} onClick={() => handleReactivateStore(record.id)}>激活</Button>
|
||||
)}
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</Card>
|
||||
|
||||
{/* 绑定店铺模态框 */}
|
||||
<Modal
|
||||
title="绑定店铺"
|
||||
visible={bindingModalVisible}
|
||||
onCancel={() => setBindingModalVisible(false)}
|
||||
footer={null}
|
||||
>
|
||||
<Form form={form} layout="vertical" onFinish={handleBindStore}>
|
||||
<Form.Item name="merchantId" label="商户ID" rules={[{ required: true, message: '请输入商户ID' }]} initialValue={merchantId}>
|
||||
<Input placeholder="请输入商户ID" />
|
||||
</Form.Item>
|
||||
<Form.Item name="platform" label="平台" rules={[{ required: true, message: '请选择平台' }]}>
|
||||
<Select placeholder="请选择平台" onChange={() => form.resetFields(['accessKey', 'secretKey', 'sellerId', 'marketplaceId', 'partnerId', 'partnerKey', 'shopId', 'appKey', 'appSecret', 'accessToken', 'appId', 'clientId', 'clientSecret', 'refreshToken', 'apiKey', 'apiSecret'])}>
|
||||
{platforms.map(platform => (
|
||||
<Option key={platform.value} value={platform.value}>{platform.label}</Option>
|
||||
))}
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<Form.Item name="platformShopId" label="平台店铺ID" rules={[{ required: true, message: '请输入平台店铺ID' }]}>
|
||||
<Input placeholder="请输入平台店铺ID" />
|
||||
</Form.Item>
|
||||
<Form.Item name="name" label="店铺名称" rules={[{ required: true, message: '请输入店铺名称' }]}>
|
||||
<Input placeholder="请输入店铺名称" />
|
||||
</Form.Item>
|
||||
<Form.Item name="description" label="店铺描述">
|
||||
<TextArea placeholder="请输入店铺描述" rows={3} />
|
||||
</Form.Item>
|
||||
<Divider orientation="left">授权信息</Divider>
|
||||
<Form.Item name="platform" noStyle shouldUpdate>
|
||||
{({ getFieldValue }) => {
|
||||
const platform = getFieldValue('platform');
|
||||
return platform ? renderAuthInfoForm(platform) : null;
|
||||
}}
|
||||
</Form.Item>
|
||||
<Form.Item>
|
||||
<Space style={{ width: '100%', justifyContent: 'flex-end' }}>
|
||||
<Button onClick={() => setBindingModalVisible(false)}>取消</Button>
|
||||
<Button type="primary" htmlType="submit" loading={loading}>
|
||||
绑定
|
||||
</Button>
|
||||
</Space>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Modal>
|
||||
|
||||
{/* 店铺详情模态框 */}
|
||||
{currentStore && (
|
||||
<Modal
|
||||
title="店铺详情"
|
||||
visible={!!currentStore}
|
||||
onCancel={() => setCurrentStore(null)}
|
||||
footer={null}
|
||||
>
|
||||
<Card>
|
||||
<Card.Meta title={currentStore.name} description={`平台: ${platforms.find(p => p.value === currentStore.platform)?.label || currentStore.platform}`} />
|
||||
<Divider />
|
||||
<p><strong>商户ID:</strong> {currentStore.merchantId}</p>
|
||||
<p><strong>平台店铺ID:</strong> {currentStore.platformShopId}</p>
|
||||
<p><strong>状态:</strong> <Tag color={statusMap[currentStore.status as keyof typeof statusMap]?.color || 'default'}>{statusMap[currentStore.status as keyof typeof statusMap]?.text || currentStore.status}</Tag></p>
|
||||
<p><strong>描述:</strong> {currentStore.description || '无'}</p>
|
||||
<p><strong>创建时间:</strong> {currentStore.created_at}</p>
|
||||
<p><strong>更新时间:</strong> {currentStore.updated_at}</p>
|
||||
<Divider />
|
||||
<Space style={{ width: '100%', justifyContent: 'flex-end' }}>
|
||||
<Button onClick={() => setCurrentStore(null)}>关闭</Button>
|
||||
</Space>
|
||||
</Card>
|
||||
</Modal>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default OperationAgent;
|
||||
16
dashboard/src/router.tsx
Normal file
16
dashboard/src/router.tsx
Normal file
@@ -0,0 +1,16 @@
|
||||
import React from 'react';
|
||||
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
|
||||
import OperationAgent from './pages/OperationAgent';
|
||||
|
||||
const AppRouter: React.FC = () => {
|
||||
return (
|
||||
<Router>
|
||||
<Routes>
|
||||
<Route path="/" element={<OperationAgent />} />
|
||||
<Route path="/operation-agent" element={<OperationAgent />} />
|
||||
</Routes>
|
||||
</Router>
|
||||
);
|
||||
};
|
||||
|
||||
export default AppRouter;
|
||||
57
dashboard/src/services/http.ts
Normal file
57
dashboard/src/services/http.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import axios from 'axios';
|
||||
|
||||
// 创建axios实例
|
||||
const http = axios.create({
|
||||
baseURL: 'http://localhost:3000', // 后端API基础URL
|
||||
timeout: 10000, // 请求超时时间
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
// 请求拦截器
|
||||
http.interceptors.request.use(
|
||||
(config) => {
|
||||
// 可以在这里添加token等认证信息
|
||||
// const token = localStorage.getItem('token');
|
||||
// if (token) {
|
||||
// config.headers.Authorization = `Bearer ${token}`;
|
||||
// }
|
||||
return config;
|
||||
},
|
||||
(error) => {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
// 响应拦截器
|
||||
http.interceptors.response.use(
|
||||
(response) => {
|
||||
return response;
|
||||
},
|
||||
(error) => {
|
||||
// 处理错误响应
|
||||
if (error.response) {
|
||||
switch (error.response.status) {
|
||||
case 401:
|
||||
// 未授权处理
|
||||
break;
|
||||
case 403:
|
||||
// 禁止访问处理
|
||||
break;
|
||||
case 404:
|
||||
// 资源不存在处理
|
||||
break;
|
||||
case 500:
|
||||
// 服务器错误处理
|
||||
break;
|
||||
default:
|
||||
// 其他错误处理
|
||||
break;
|
||||
}
|
||||
}
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
export { http };
|
||||
95
dashboard/src/services/operationAgentService.ts
Normal file
95
dashboard/src/services/operationAgentService.ts
Normal file
@@ -0,0 +1,95 @@
|
||||
import { http } from './http';
|
||||
|
||||
export interface StoreBindingData {
|
||||
merchantId: string;
|
||||
platform: string;
|
||||
platformShopId: string;
|
||||
name: string;
|
||||
description?: string;
|
||||
authInfo: Record<string, any>;
|
||||
}
|
||||
|
||||
export interface Store {
|
||||
id: string;
|
||||
merchantId: string;
|
||||
name: string;
|
||||
platform: string;
|
||||
platformShopId: string;
|
||||
description: string;
|
||||
status: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
export interface SyncResult {
|
||||
success: boolean;
|
||||
count: number;
|
||||
}
|
||||
|
||||
export class OperationAgentService {
|
||||
/**
|
||||
* 绑定店铺
|
||||
*/
|
||||
async bindStore(data: StoreBindingData): Promise<Store> {
|
||||
const response = await http.post<Store>('/api/operation-agent/stores', data);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取商户的店铺列表
|
||||
*/
|
||||
async getStores(merchantId: string): Promise<Store[]> {
|
||||
const response = await http.get<Store[]>(`/api/operation-agent/stores/${merchantId}`);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取店铺详情
|
||||
*/
|
||||
async getStore(storeId: string): Promise<Store> {
|
||||
const response = await http.get<Store>(`/api/operation-agent/stores/detail/${storeId}`);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步店铺商品
|
||||
*/
|
||||
async syncProducts(storeId: string): Promise<SyncResult> {
|
||||
const response = await http.post<SyncResult>(`/api/operation-agent/stores/${storeId}/products/sync`);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步店铺订单
|
||||
*/
|
||||
async syncOrders(storeId: string): Promise<SyncResult> {
|
||||
const response = await http.post<SyncResult>(`/api/operation-agent/stores/${storeId}/orders/sync`);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新商品价格
|
||||
*/
|
||||
async updateProductPrice(storeId: string, productId: string, price: number): Promise<boolean> {
|
||||
const response = await http.put<boolean>(`/api/operation-agent/stores/${storeId}/products/${productId}/price`, { price });
|
||||
return response.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 停用店铺
|
||||
*/
|
||||
async deactivateStore(storeId: string): Promise<Store> {
|
||||
const response = await http.put<Store>(`/api/operation-agent/stores/${storeId}/deactivate`);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 重新激活店铺
|
||||
*/
|
||||
async reactivateStore(storeId: string): Promise<Store> {
|
||||
const response = await http.put<Store>(`/api/operation-agent/stores/${storeId}/reactivate`);
|
||||
return response.data;
|
||||
}
|
||||
}
|
||||
|
||||
export const operationAgentService = new OperationAgentService();
|
||||
Reference in New Issue
Block a user