Merge branch 'yongpxu-dev' into yongpxu-dev2
This commit is contained in:
@@ -7,38 +7,14 @@ import dayjs from "dayjs";
|
||||
import "dayjs/locale/zh-cn";
|
||||
import App from "./App";
|
||||
import "./styles/global.scss";
|
||||
import { db } from "@/utils/db"; // 引入数据库实例
|
||||
|
||||
// 设置dayjs为中文
|
||||
dayjs.locale("zh-cn");
|
||||
|
||||
// 数据库初始化
|
||||
async function initializeApp() {
|
||||
try {
|
||||
// 确保数据库已打开
|
||||
await db.open();
|
||||
console.log("数据库初始化成功");
|
||||
|
||||
// 调试模式:清理所有数据
|
||||
console.log("调试模式:开始清理数据库数据...");
|
||||
await db.kfUsers.clear();
|
||||
await db.weChatGroup.clear();
|
||||
await db.contracts.clear();
|
||||
await db.newContractList.clear();
|
||||
console.log("数据库数据清理完成");
|
||||
} catch (error) {
|
||||
console.error("数据库初始化失败:", error);
|
||||
// 可以选择显示错误提示或使用降级方案
|
||||
}
|
||||
|
||||
// 渲染应用
|
||||
const root = createRoot(document.getElementById("root")!);
|
||||
root.render(
|
||||
<ConfigProvider locale={zhCN}>
|
||||
<App />
|
||||
</ConfigProvider>,
|
||||
);
|
||||
}
|
||||
|
||||
// 启动应用
|
||||
initializeApp();
|
||||
// 渲染应用
|
||||
const root = createRoot(document.getElementById("root")!);
|
||||
root.render(
|
||||
<ConfigProvider locale={zhCN}>
|
||||
<App />
|
||||
</ConfigProvider>,
|
||||
);
|
||||
|
||||
35
Cunkebao/src/pages/mobile/mine/recharge/index/api.ts
Normal file
35
Cunkebao/src/pages/mobile/mine/recharge/index/api.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import request from "@/api/request";
|
||||
|
||||
interface taocanItem {
|
||||
id: 1;
|
||||
name: "试用套餐";
|
||||
tokens: "2,800";
|
||||
price: 9800;
|
||||
originalPrice: 140;
|
||||
description: ["适合新用户体验", "包含基础AI功能", "永久有效", "客服支持"];
|
||||
sort: 1;
|
||||
isTrial: 1;
|
||||
isRecommend: 0;
|
||||
isHot: 0;
|
||||
isVip: 0;
|
||||
status: 1;
|
||||
isDel: 0;
|
||||
delTime: null;
|
||||
createTime: "2025-09-29 16:53:06";
|
||||
updateTime: "2025-09-29 16:53:06";
|
||||
discount: 30;
|
||||
unitPrice: 3.5;
|
||||
}
|
||||
|
||||
interface taocanList {
|
||||
list: taocanItem[];
|
||||
}
|
||||
// 套餐列表
|
||||
export function getTaocanList(): Promise<taocanList> {
|
||||
return request("/v1/tokens/list", {}, "GET");
|
||||
}
|
||||
|
||||
// 支付id和price 从套餐列表取对应的价格
|
||||
export function pay(params: { id: string; price: number }) {
|
||||
return request("/v1/tokens/pay", params, "POST");
|
||||
}
|
||||
@@ -123,10 +123,18 @@
|
||||
margin: 4px 0;
|
||||
font-size: 16px;
|
||||
border-radius: 8px;
|
||||
padding: 12px 16px;
|
||||
|
||||
div {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
.quick-btn-active {
|
||||
@extend .quick-btn;
|
||||
font-weight: 600;
|
||||
border: 2px solid var(--primary-color);
|
||||
}
|
||||
.recharge-main-btn {
|
||||
margin-top: 16px;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React, { useState } from "react";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { Card, Button, Toast, Tabs } from "antd-mobile";
|
||||
import { useUserStore } from "@/store/module/user";
|
||||
import { Card, Button, Toast, Tabs, Dialog } from "antd-mobile";
|
||||
import style from "./index.module.scss";
|
||||
import {
|
||||
WalletOutlined,
|
||||
@@ -12,36 +11,7 @@ import {
|
||||
} from "@ant-design/icons";
|
||||
import NavCommon from "@/components/NavCommon";
|
||||
import Layout from "@/components/Layout/Layout";
|
||||
|
||||
const quickAmounts = [50, 100, 200, 500, 1000];
|
||||
|
||||
// AI服务套餐数据
|
||||
const aiServicePackages = [
|
||||
{
|
||||
id: 1,
|
||||
name: "入门套餐",
|
||||
tag: "推荐",
|
||||
tagColor: "blue",
|
||||
description: "适合个人用户体验AI服务",
|
||||
usage: "可使用AI服务约110次",
|
||||
price: 100,
|
||||
originalPrice: 110,
|
||||
gift: 10,
|
||||
actualAmount: 110,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "标准套餐",
|
||||
tag: "热门",
|
||||
tagColor: "green",
|
||||
description: "适合小团队日常使用",
|
||||
usage: "可使用AI服务约580次",
|
||||
price: 500,
|
||||
originalPrice: 580,
|
||||
gift: 80,
|
||||
actualAmount: 580,
|
||||
},
|
||||
];
|
||||
import { getTaocanList, pay } from "./api";
|
||||
|
||||
// AI服务列表数据
|
||||
const aiServices = [
|
||||
@@ -120,25 +90,77 @@ const versionPackages = [
|
||||
|
||||
const Recharge: React.FC = () => {
|
||||
const navigate = useNavigate();
|
||||
const { user } = useUserStore();
|
||||
// 假设余额从后端接口获取,实际可用props或store传递
|
||||
const [balance, setBalance] = useState(0);
|
||||
const [selected, setSelected] = useState<number | null>(null);
|
||||
const [balance] = useState(0);
|
||||
const [selected, setSelected] = useState<any | null>(null);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [activeTab, setActiveTab] = useState("account");
|
||||
const [taocanList, setTaocanList] = useState<any[]>([]);
|
||||
|
||||
// 加载套餐列表
|
||||
useEffect(() => {
|
||||
const loadTaocanList = async () => {
|
||||
try {
|
||||
const res = await getTaocanList();
|
||||
if (res.list) {
|
||||
setTaocanList(res.list);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("加载套餐列表失败:", error);
|
||||
Toast.show({ content: "加载套餐列表失败", position: "top" });
|
||||
}
|
||||
};
|
||||
loadTaocanList();
|
||||
}, []);
|
||||
|
||||
// 充值操作
|
||||
const handleRecharge = async () => {
|
||||
if (!selected) {
|
||||
Toast.show({ content: "请选择充值金额", position: "top" });
|
||||
Toast.show({ content: "请选择充值套餐", position: "top" });
|
||||
return;
|
||||
}
|
||||
setLoading(true);
|
||||
setTimeout(() => {
|
||||
setBalance(b => b + selected);
|
||||
Toast.show({ content: `充值成功,已到账¥${selected}` });
|
||||
try {
|
||||
const res = await pay({
|
||||
id: selected.id,
|
||||
price: selected.price,
|
||||
});
|
||||
// 假设返回的是二维码链接,存储在res中
|
||||
if (res) {
|
||||
// 显示二维码弹窗
|
||||
Dialog.show({
|
||||
content: (
|
||||
<div style={{ textAlign: "center", padding: "20px" }}>
|
||||
<div
|
||||
style={{
|
||||
marginBottom: "16px",
|
||||
fontSize: "16px",
|
||||
fontWeight: "500",
|
||||
}}
|
||||
>
|
||||
请使用微信扫码支付
|
||||
</div>
|
||||
<img
|
||||
src={res.code_url as any}
|
||||
alt="支付二维码"
|
||||
style={{ width: "250px", height: "250px", margin: "0 auto" }}
|
||||
/>
|
||||
<div
|
||||
style={{ marginTop: "16px", color: "#666", fontSize: "14px" }}
|
||||
>
|
||||
支付金额: ¥{selected.price / 100}
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
closeOnMaskClick: true,
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("支付失败:", error);
|
||||
Toast.show({ content: "支付失败,请重试", position: "top" });
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}, 1200);
|
||||
}
|
||||
};
|
||||
|
||||
// 渲染账户充值tab内容
|
||||
@@ -156,23 +178,80 @@ const Recharge: React.FC = () => {
|
||||
</div>
|
||||
</Card>
|
||||
<Card className={style["quick-card"]}>
|
||||
<div className={style["quick-title"]}>快捷充值</div>
|
||||
<div className={style["quick-title"]}>选择套餐</div>
|
||||
<div className={style["quick-list"]}>
|
||||
{quickAmounts.map(amt => (
|
||||
{taocanList.map(item => (
|
||||
<Button
|
||||
key={amt}
|
||||
color={selected === amt ? "primary" : "default"}
|
||||
key={item.id}
|
||||
color={selected?.id === item.id ? "primary" : "default"}
|
||||
className={
|
||||
selected === amt
|
||||
selected?.id === item.id
|
||||
? style["quick-btn-active"]
|
||||
: style["quick-btn"]
|
||||
}
|
||||
onClick={() => setSelected(amt)}
|
||||
onClick={() => setSelected(item)}
|
||||
>
|
||||
¥{amt}
|
||||
<div>
|
||||
<div>¥{item.price / 100}</div>
|
||||
{item.discount && (
|
||||
<div style={{ fontSize: "12px", color: "#999" }}>
|
||||
{item.discount}折
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
{selected && (
|
||||
<div
|
||||
style={{
|
||||
marginBottom: "12px",
|
||||
padding: "12px",
|
||||
background: "#f5f5f5",
|
||||
borderRadius: "8px",
|
||||
}}
|
||||
>
|
||||
<div style={{ marginBottom: "6px" }}>
|
||||
<span style={{ fontWeight: "500" }}>{selected.name}</span>
|
||||
{selected.isRecommend === 1 && (
|
||||
<span
|
||||
style={{
|
||||
marginLeft: "8px",
|
||||
fontSize: "12px",
|
||||
color: "#1890ff",
|
||||
}}
|
||||
>
|
||||
推荐
|
||||
</span>
|
||||
)}
|
||||
{selected.isHot === 1 && (
|
||||
<span
|
||||
style={{
|
||||
marginLeft: "8px",
|
||||
fontSize: "12px",
|
||||
color: "#ff4d4f",
|
||||
}}
|
||||
>
|
||||
热门
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div style={{ fontSize: "14px", color: "#666" }}>
|
||||
包含 {selected.tokens} Tokens
|
||||
</div>
|
||||
{selected.originalPrice && (
|
||||
<div
|
||||
style={{
|
||||
fontSize: "12px",
|
||||
color: "#999",
|
||||
textDecoration: "line-through",
|
||||
}}
|
||||
>
|
||||
原价: ¥{selected.originalPrice / 100}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<Button
|
||||
block
|
||||
color="primary"
|
||||
|
||||
@@ -1,319 +0,0 @@
|
||||
/**
|
||||
* 数据库工具类 - 使用serverId作为主键的优化架构
|
||||
*
|
||||
* 架构设计:
|
||||
* 1. 使用serverId作为数据库主键,直接对应接口返回的id字段
|
||||
* 2. 保留原始的id字段,用于存储接口数据的完整性
|
||||
* 3. 简化数据处理逻辑,避免ID映射的复杂性
|
||||
*
|
||||
* 优势:
|
||||
* - 直接使用服务器ID作为主键,避免ID冲突
|
||||
* - 保持数据的一致性和可追溯性
|
||||
* - 简化查询逻辑,提高性能
|
||||
* - 支持重复数据检测和去重
|
||||
*
|
||||
* 使用方法:
|
||||
* - 存储接口数据:使用 createWithServerId() 或 createManyWithServerId()
|
||||
* - 查询数据:使用 findById(id) 根据原始ID查询,或 findByPrimaryKey(serverId) 根据主键查询
|
||||
* - 批量查询:使用 findByIds([id1, id2, ...]) 根据原始ID批量查询
|
||||
* - 内部操作:serverId作为主键用于数据库内部管理
|
||||
*
|
||||
* 示例:
|
||||
* const serverData = { id: 1001, name: '测试', ... }; // 接口返回的数据
|
||||
* const serverId = await service.createWithServerId(serverData); // 存储,返回serverId
|
||||
* const data = await service.findById(1001); // 根据原始ID查询(用户友好)
|
||||
* const dataByPK = await service.findByPrimaryKey(serverId); // 根据主键查询(内部使用)
|
||||
*/
|
||||
|
||||
import Dexie, { Table } from "dexie";
|
||||
import {
|
||||
KfUserListData,
|
||||
weChatGroup,
|
||||
ContractData,
|
||||
MessageListData,
|
||||
} from "@/pages/pc/ckbox/data";
|
||||
|
||||
// 数据类型定义,使用serverId作为主键
|
||||
export interface KfUserWithServerId extends Omit<KfUserListData, "id"> {
|
||||
serverId: number | string; // 服务器ID作为主键
|
||||
id?: number; // 接口数据的原始ID字段
|
||||
}
|
||||
|
||||
// 新联系人列表数据接口
|
||||
export interface NewContactListData {
|
||||
serverId: number | string; // 服务器ID作为主键
|
||||
id?: number; // 接口数据的原始ID字段
|
||||
groupName: string;
|
||||
contacts: ContractData[];
|
||||
weChatGroup: weChatGroup[];
|
||||
}
|
||||
|
||||
// 数据库类
|
||||
class CunkebaoDatabase extends Dexie {
|
||||
kfUsers!: Table<KfUserWithServerId>;
|
||||
weChatGroup!: Table<weChatGroup>;
|
||||
contracts!: Table<ContractData>;
|
||||
newContractList!: Table<NewContactListData>;
|
||||
messageList!: Table<MessageListData>;
|
||||
|
||||
constructor() {
|
||||
super("CunkebaoDatabase");
|
||||
|
||||
// 版本1:使用serverId作为主键的架构
|
||||
this.version(1).stores({
|
||||
kfUsers:
|
||||
"serverId, id, tenantId, wechatId, nickname, alias, avatar, gender, region, signature, bindQQ, bindEmail, bindMobile, createTime, currentDeviceId, isDeleted, deleteTime, groupId, memo, wechatVersion, lastUpdateTime, isOnline",
|
||||
weChatGroup:
|
||||
"serverId, id, wechatAccountId, tenantId, accountId, chatroomId, chatroomOwner, conRemark, nickname, chatroomAvatar,wechatChatroomId, groupId, config, unreadCount, notice, selfDisplyName",
|
||||
contracts:
|
||||
"serverId, id, wechatAccountId, wechatId, alias, conRemark, nickname, quanPin, avatar, gender, region, addFrom, phone, signature, accountId, extendFields, city, lastUpdateTime, isPassed, tenantId, groupId, thirdParty, additionalPicture, desc, config, lastMessageTime, unreadCount, duplicate",
|
||||
newContractList: "serverId, id, groupName, contacts",
|
||||
messageList:
|
||||
"serverId, id, dataType, wechatAccountId, tenantId, accountId, nickname, avatar, groupId, config, labels, unreadCount, wechatId, alias, conRemark, quanPin, gender, region, addFrom, phone, signature, extendFields, city, lastUpdateTime, isPassed, thirdParty, additionalPicture, desc, lastMessageTime, duplicate, chatroomId, chatroomOwner, chatroomAvatar, notice, selfDisplyName",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 创建数据库实例
|
||||
export const db = new CunkebaoDatabase();
|
||||
|
||||
// 简单的数据库操作类
|
||||
export class DatabaseService<T> {
|
||||
constructor(private table: Table<T>) {}
|
||||
|
||||
// 基础 CRUD 操作 - 使用serverId作为主键
|
||||
async create(data: Omit<T, "serverId">): Promise<string | number> {
|
||||
return await this.table.add(data as T);
|
||||
}
|
||||
|
||||
// 创建数据(直接使用接口数据)
|
||||
// 接口数据的id字段直接作为serverId主键,原id字段保留
|
||||
async createWithServerId(data: any): Promise<string | number> {
|
||||
const dataToInsert = {
|
||||
...data,
|
||||
serverId: data.id, // 使用接口的id作为serverId主键
|
||||
};
|
||||
return await this.table.add(dataToInsert as T);
|
||||
}
|
||||
|
||||
// 根据原始ID查询(用户友好的查询方法)
|
||||
async findById(id: string | number): Promise<T | undefined> {
|
||||
return await this.table.where("id").equals(id).first();
|
||||
}
|
||||
|
||||
// 根据serverId查询(内部主键查询)
|
||||
async findByPrimaryKey(serverId: string | number): Promise<T | undefined> {
|
||||
return await this.table.get(serverId);
|
||||
}
|
||||
|
||||
async findAll(): Promise<T[]> {
|
||||
return await this.table.toArray();
|
||||
}
|
||||
|
||||
async update(serverId: string | number, data: Partial<T>): Promise<number> {
|
||||
return await this.table.update(serverId, data as any);
|
||||
}
|
||||
|
||||
async updateMany(
|
||||
dataList: { serverId: string | number; data: Partial<T> }[],
|
||||
): Promise<number> {
|
||||
return await this.table.bulkUpdate(
|
||||
dataList.map(item => ({
|
||||
key: item.serverId,
|
||||
changes: item.data as any,
|
||||
})),
|
||||
);
|
||||
}
|
||||
|
||||
async createMany(
|
||||
dataList: Omit<T, "serverId">[],
|
||||
): Promise<(string | number)[]> {
|
||||
return await this.table.bulkAdd(dataList as T[], { allKeys: true });
|
||||
}
|
||||
|
||||
// 批量创建数据(直接使用接口数据)
|
||||
// 接口数据的id字段直接作为serverId主键
|
||||
async createManyWithServerId(dataList: any[]): Promise<(string | number)[]> {
|
||||
// 检查是否存在重复的serverId
|
||||
const serverIds = dataList.map(item => item.id);
|
||||
const existingData = await this.table
|
||||
.where("serverId")
|
||||
.anyOf(serverIds)
|
||||
.toArray();
|
||||
const existingServerIds = new Set(
|
||||
existingData.map((item: any) => item.serverId),
|
||||
);
|
||||
|
||||
// 过滤掉已存在的数据
|
||||
const newData = dataList.filter(item => !existingServerIds.has(item.id));
|
||||
|
||||
if (newData.length === 0) {
|
||||
console.log("所有数据都已存在,跳过插入");
|
||||
return [];
|
||||
}
|
||||
|
||||
const processedData = newData.map(item => ({
|
||||
...item,
|
||||
serverId: item.id, // 使用接口的id作为serverId主键
|
||||
}));
|
||||
|
||||
console.log(
|
||||
`插入 ${processedData.length} 条新数据,跳过 ${dataList.length - newData.length} 条重复数据`,
|
||||
);
|
||||
return await this.table.bulkAdd(processedData as T[], { allKeys: true });
|
||||
}
|
||||
|
||||
async delete(serverId: string | number): Promise<void> {
|
||||
await this.table.delete(serverId);
|
||||
}
|
||||
|
||||
async clear(): Promise<void> {
|
||||
await this.table.clear();
|
||||
}
|
||||
|
||||
// 条件查询
|
||||
async findWhere(field: keyof T, value: any): Promise<T[]> {
|
||||
return await this.table
|
||||
.where(field as string)
|
||||
.equals(value)
|
||||
.toArray();
|
||||
}
|
||||
|
||||
// 根据服务器ID查询(兼容性方法)
|
||||
async findByServerId(serverId: any): Promise<T | undefined> {
|
||||
return await this.table.get(serverId);
|
||||
}
|
||||
|
||||
// 根据原始ID批量查询
|
||||
async findByIds(ids: (string | number)[]): Promise<T[]> {
|
||||
return await this.table.where("id").anyOf(ids).toArray();
|
||||
}
|
||||
|
||||
// 多值查询(IN 查询)
|
||||
async findWhereIn(field: keyof T, values: any[]): Promise<T[]> {
|
||||
return await this.table
|
||||
.where(field as string)
|
||||
.anyOf(values)
|
||||
.toArray();
|
||||
}
|
||||
|
||||
// 范围查询
|
||||
async findWhereBetween(field: keyof T, min: any, max: any): Promise<T[]> {
|
||||
return await this.table
|
||||
.where(field as string)
|
||||
.between(min, max)
|
||||
.toArray();
|
||||
}
|
||||
|
||||
// 模糊查询(以指定字符串开头)
|
||||
async findWhereStartsWith(field: keyof T, prefix: string): Promise<T[]> {
|
||||
return await this.table
|
||||
.where(field as string)
|
||||
.startsWith(prefix)
|
||||
.toArray();
|
||||
}
|
||||
|
||||
// 不等于查询
|
||||
async findWhereNot(field: keyof T, value: any): Promise<T[]> {
|
||||
return await this.table
|
||||
.where(field as string)
|
||||
.notEqual(value)
|
||||
.toArray();
|
||||
}
|
||||
|
||||
// 大于查询
|
||||
async findWhereGreaterThan(field: keyof T, value: any): Promise<T[]> {
|
||||
return await this.table
|
||||
.where(field as string)
|
||||
.above(value)
|
||||
.toArray();
|
||||
}
|
||||
|
||||
// 小于查询
|
||||
async findWhereLessThan(field: keyof T, value: any): Promise<T[]> {
|
||||
return await this.table
|
||||
.where(field as string)
|
||||
.below(value)
|
||||
.toArray();
|
||||
}
|
||||
|
||||
// 复合条件查询
|
||||
async findWhereMultiple(
|
||||
conditions: {
|
||||
field: keyof T;
|
||||
operator: "equals" | "above" | "below" | "startsWith";
|
||||
value: any;
|
||||
}[],
|
||||
): Promise<T[]> {
|
||||
let collection = this.table.toCollection();
|
||||
|
||||
for (const condition of conditions) {
|
||||
const { field, operator, value } = condition;
|
||||
collection = collection.and(item => {
|
||||
const fieldValue = (item as any)[field];
|
||||
switch (operator) {
|
||||
case "equals":
|
||||
return fieldValue === value;
|
||||
case "above":
|
||||
return fieldValue > value;
|
||||
case "below":
|
||||
return fieldValue < value;
|
||||
case "startsWith":
|
||||
return (
|
||||
typeof fieldValue === "string" && fieldValue.startsWith(value)
|
||||
);
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return await collection.toArray();
|
||||
}
|
||||
|
||||
// 分页查询
|
||||
async findWithPagination(
|
||||
page: number = 1,
|
||||
limit: number = 10,
|
||||
): Promise<{ data: T[]; total: number; page: number; limit: number }> {
|
||||
const offset = (page - 1) * limit;
|
||||
const total = await this.table.count();
|
||||
const data = await this.table.offset(offset).limit(limit).toArray();
|
||||
|
||||
return { data, total, page, limit };
|
||||
}
|
||||
|
||||
// 排序查询
|
||||
async findAllSorted(
|
||||
field: keyof T,
|
||||
direction: "asc" | "desc" = "asc",
|
||||
): Promise<T[]> {
|
||||
const collection = this.table.orderBy(field as string);
|
||||
return direction === "desc"
|
||||
? await collection.reverse().toArray()
|
||||
: await collection.toArray();
|
||||
}
|
||||
|
||||
// 统计
|
||||
async count(): Promise<number> {
|
||||
return await this.table.count();
|
||||
}
|
||||
|
||||
// 条件统计
|
||||
async countWhere(field: keyof T, value: any): Promise<number> {
|
||||
return await this.table
|
||||
.where(field as string)
|
||||
.equals(value)
|
||||
.count();
|
||||
}
|
||||
}
|
||||
|
||||
// 创建各表的服务实例
|
||||
export const kfUserService = new DatabaseService(db.kfUsers);
|
||||
export const weChatGroupService = new DatabaseService(db.weChatGroup);
|
||||
export const contractService = new DatabaseService(db.contracts);
|
||||
export const newContactListService = new DatabaseService(db.newContractList);
|
||||
export const messageListService = new DatabaseService(db.messageList);
|
||||
|
||||
// 默认导出数据库实例
|
||||
export default db;
|
||||
Reference in New Issue
Block a user