Merge remote-tracking branch 'yudao/dev' into dev

This commit is contained in:
jason
2025-11-20 13:32:53 +08:00
727 changed files with 20322 additions and 21931 deletions

View File

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

View File

Before

Width:  |  Height:  |  Size: 348 KiB

After

Width:  |  Height:  |  Size: 348 KiB

View File

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB

View File

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View File

Before

Width:  |  Height:  |  Size: 238 KiB

After

Width:  |  Height:  |  Size: 238 KiB

View File

Before

Width:  |  Height:  |  Size: 139 KiB

After

Width:  |  Height:  |  Size: 139 KiB

View File

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 69 KiB

View File

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

Before

Width:  |  Height:  |  Size: 201 KiB

After

Width:  |  Height:  |  Size: 201 KiB

View File

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 60 KiB

View File

Before

Width:  |  Height:  |  Size: 196 KiB

After

Width:  |  Height:  |  Size: 196 KiB

View File

Before

Width:  |  Height:  |  Size: 495 KiB

After

Width:  |  Height:  |  Size: 495 KiB

View File

Before

Width:  |  Height:  |  Size: 177 KiB

After

Width:  |  Height:  |  Size: 177 KiB

View File

Before

Width:  |  Height:  |  Size: 126 KiB

After

Width:  |  Height:  |  Size: 126 KiB

View File

@@ -1,89 +0,0 @@
## Git Commit Message Convention
> This is adapted from [Angular's commit convention](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-angular).
#### TL;DR:
Messages must be matched by the following regex:
```js
/^(revert: )?(feat|fix|docs|style|refactor|perf|test|workflow|build|ci|chore|types|wip): .{1,50}/;
```
#### Examples
Appears under "Features" header, `dev` subheader:
```
feat(dev): add 'comments' option
```
Appears under "Bug Fixes" header, `dev` subheader, with a link to issue #28:
```
fix(dev): fix dev error
close #28
```
Appears under "Performance Improvements" header, and under "Breaking Changes" with the breaking change explanation:
```
perf(build): remove 'foo' option
BREAKING CHANGE: The 'foo' option has been removed.
```
The following commit and commit `667ecc1` do not appear in the changelog if they are under the same release. If not, the revert commit appears under the "Reverts" header.
```
revert: feat(compiler): add 'comments' option
This reverts commit 667ecc1654a317a13331b17617d973392f415f02.
```
### Full Message Format
A commit message consists of a **header**, **body** and **footer**. The header has a **type**, **scope** and **subject**:
```
<type>(<scope>): <subject>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>
```
The **header** is mandatory and the **scope** of the header is optional.
### Revert
If the commit reverts a previous commit, it should begin with `revert: `, followed by the header of the reverted commit. In the body, it should say: `This reverts commit <hash>.`, where the hash is the SHA of the commit being reverted.
### Type
If the prefix is `feat`, `fix` or `perf`, it will appear in the changelog. However, if there is any [BREAKING CHANGE](#footer), the commit will always appear in the changelog.
Other prefixes are up to your discretion. Suggested prefixes are `docs`, `chore`, `style`, `refactor`, and `test` for non-changelog related tasks.
### Scope
The scope could be anything specifying the place of the commit change. For example `dev`, `build`, `workflow`, `cli` etc...
### Subject
The subject contains a succinct description of the change:
- use the imperative, present tense: "change" not "changed" nor "changes"
- don't capitalize the first letter
- no dot (.) at the end
### Body
Just as in the **subject**, use the imperative, present tense: "change" not "changed" nor "changes". The body should include the motivation for the change and contrast this with previous behavior.
### Footer
The footer should contain any information about **Breaking Changes** and is also the place to reference GitHub issues that this commit **Closes**.
**Breaking Changes** should start with the word `BREAKING CHANGE:` with a space or two newlines. The rest of the commit message is then used for this.

9
.vscode/launch.json vendored
View File

@@ -2,15 +2,6 @@
"$schema": "https://json.schemastore.org/launchsettings.json",
"version": "0.2.0",
"configurations": [
{
"type": "chrome",
"name": "vben admin playground dev",
"request": "launch",
"url": "http://localhost:5555",
"env": { "NODE_ENV": "development" },
"sourceMaps": true,
"webRoot": "${workspaceFolder}/playground"
},
{
"type": "chrome",
"name": "vben admin antd dev",

View File

@@ -1,56 +0,0 @@
version: '1.0'
name: pipeline-20251103
displayName: master-build
triggers:
trigger: auto
push:
branches:
prefix:
- ''
pr:
branches:
prefix:
- ''
schedule:
- cron: '* * * 1 * ? *'
stages:
- name: stage-72bb5db9
displayName: build
strategy: naturally
trigger: auto
executor: []
steps:
- step: build@nodejs
name: build_nodejs
displayName: Nodejs 构建
nodeVersion: 24.5.0
commands:
- '# 设置NPM源提升安装速度'
- npm config set registry https://registry.npmmirror.com
- '# 安装pnpm'
- npm add -g pnpm
- '# 安装依赖'
- pnpm i
- '# 检查lint'
- pnpm lint
- '# 检查check'
- pnpm check
- '# 执行编译命令antd'
- pnpm build:antd
- '# 执行编译命令ele'
- pnpm build:ele
- '# 执行编译命令naive'
- pnpm build:naive
artifacts:
- name: BUILD_ARTIFACT
path:
- ./apps/web-antd/dist/
- ./apps/web-ele/dist/
- ./apps/web-naive/dist/
caches:
- ~/.npm
- ~/.yarn
- ~/.pnpm
notify: []
strategy:
retry: '0'

View File

@@ -23,7 +23,7 @@
- 采用最新 [vue-vben-admin](https://github.com/vbenjs/vue-vben-admin) v5 实现
- 支持 [Ant Design Vue](https://www.antdv.com/) | [Element Plus](https://element-plus.org/zh-CN/) | [Naive UI](https://www.naiveui.com/) | [TDesign](https://tdesign.tencent.com/) 多种免费开源的中后台模版,具备如下特性:
![首页](.image/demo/vben.png)
![首页](.gitee/image/demo/vben.png)
- **最新技术栈**:使用 Vue3、Vite6 等前端前沿技术开发
- **TypeScript**: 应用程序级 JavaScript 的语言
@@ -33,9 +33,9 @@
- **组件**:二次封装了多个常用的组件
- **示例**:内置丰富的示例
## 外包项目请联系【非项目需求请勿扫码,非客服,不解答项目问题】
## [外包项目请联系【非项目需求请勿扫码,非客服,不解答项目问题】](https://www.shuduokeji.com)
![alt 软件定制开发 数舵科技](.image/wx-xingyu.png)
![alt 软件定制开发 数舵科技](.gitee/image/wx-xingyu.png)
## 技术栈
@@ -68,11 +68,11 @@
① Spring Boot 单体架构:<https://doc.iocoder.cn>
![架构图](/.image/common/ruoyi-vue-pro-architecture.png)
![架构图](/.gitee/image/common/ruoyi-vue-pro-architecture.png)
② Spring Cloud 微服务架构:<https://cloud.iocoder.cn>
![架构图](/.image/common/yudao-cloud-architecture.png)
![架构图](/.gitee/image/common/yudao-cloud-architecture.png)
## 内置功能
@@ -80,7 +80,7 @@
系统内置多种多种业务功能,可以用于快速你的业务系统:
![功能分层](/.image/common/ruoyi-vue-pro-biz.png)
![功能分层](/.gitee/image/common/ruoyi-vue-pro-biz.png)
- 通用模块(必选):系统功能、基础设施
- 通用模块(可选):工作流程、支付系统、数据报表、会员中心
@@ -110,17 +110,17 @@
| 🚀 | 应用管理 | 管理 SSO 单点登录的应用,支持多种 OAuth2 授权方式 |
| 🚀 | 地区管理 | 展示省份、城市、区镇等城市信息,支持 IP 对应城市 |
![功能图](/.image/common/system-feature.png)
![功能图](/.gitee/image/common/system-feature.png)
### 工作流程
![功能图](/.image/common/bpm-feature.png)
![功能图](/.gitee/image/common/bpm-feature.png)
基于 Flowable 构建,可支持信创(国产)数据库,满足中国特色流程操作:
| BPMN 设计器 | 钉钉/飞书设计器 |
| --- | --- |
| ![工作流设计器](.image/工作流设计器-bpmn.jpg) | ![工作流设计器](.image/工作流设计器-simple.jpg) |
| ![工作流设计器](.gitee/image/工作流设计器-bpmn.jpg) | ![工作流设计器](.gitee/image/工作流设计器-simple.jpg) |
> 历经头部企业生产验证,工作流引擎须标配仿钉钉/飞书 + BPMN 双设计器!!!
>
@@ -186,7 +186,7 @@
| 🚀 | 日志服务 | 轻量级日志中心,查看远程服务器的日志 |
| 🚀 | 单元测试 | 基于 JUnit + Mockito 实现单元测试,保证功能的正确性、代码的质量等 |
![功能图](/.image/common/infra-feature.png)
![功能图](/.gitee/image/common/infra-feature.png)
### 数据报表
@@ -214,26 +214,26 @@
演示地址:<https://doc.iocoder.cn/mall-preview/>
![功能图](/.image/common/mall-feature.png)
![功能图](/.gitee/image/common/mall-feature.png)
![功能图](/.image/common/mall-preview.png)
![功能图](/.gitee/image/common/mall-preview.png)
### ERP 系统
演示地址:<https://doc.iocoder.cn/erp-preview/>
![功能图](/.image/common/erp-feature.png)
![功能图](/.gitee/image/common/erp-feature.png)
### CRM 系统
演示地址:<https://doc.iocoder.cn/crm-preview/>
![功能图](/.image/common/crm-feature.png)
![功能图](/.gitee/image/common/crm-feature.png)
### AI 大模型
演示地址:<https://doc.iocoder.cn/ai-preview/>
![功能图](/.image/common/ai-feature.png)
![功能图](/.gitee/image/common/ai-feature.png)
![功能图](/.image/common/ai-preview.gif)
![功能图](/.gitee/image/common/ai-preview.gif)

View File

@@ -1,3 +0,0 @@
PORT=5320
ACCESS_TOKEN_SECRET=access_token_secret
REFRESH_TOKEN_SECRET=refresh_token_secret

View File

@@ -1,15 +0,0 @@
# @vben/backend-mock
## Description
Vben Admin 数据 mock 服务,没有对接任何的数据库,所有数据都是模拟的,用于前端开发时提供数据支持。线上环境不再提供 mock 集成,可自行部署服务或者对接真实数据,由于 `mock.js` 等工具有一些限制,比如上传文件不行、无法模拟复杂的逻辑等,所以这里使用了真实的后端服务来实现。唯一麻烦的是本地需要同时启动后端服务和前端服务,但是这样可以更好的模拟真实环境。该服务不需要手动启动,已经集成在 vite 插件内,随应用一起启用。
## Running the app
```bash
# development
$ pnpm run start
# production mode
$ pnpm run build
```

View File

@@ -1,16 +0,0 @@
import { eventHandler } from 'h3';
import { verifyAccessToken } from '~/utils/jwt-utils';
import { MOCK_CODES } from '~/utils/mock-data';
import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';
export default eventHandler((event) => {
const userinfo = verifyAccessToken(event);
if (!userinfo) {
return unAuthorizedResponse(event);
}
const codes =
MOCK_CODES.find((item) => item.username === userinfo.username)?.codes ?? [];
return useResponseSuccess(codes);
});

View File

@@ -1,42 +0,0 @@
import { defineEventHandler, readBody, setResponseStatus } from 'h3';
import {
clearRefreshTokenCookie,
setRefreshTokenCookie,
} from '~/utils/cookie-utils';
import { generateAccessToken, generateRefreshToken } from '~/utils/jwt-utils';
import { MOCK_USERS } from '~/utils/mock-data';
import {
forbiddenResponse,
useResponseError,
useResponseSuccess,
} from '~/utils/response';
export default defineEventHandler(async (event) => {
const { password, username } = await readBody(event);
if (!password || !username) {
setResponseStatus(event, 400);
return useResponseError(
'BadRequestException',
'Username and password are required',
);
}
const findUser = MOCK_USERS.find(
(item) => item.username === username && item.password === password,
);
if (!findUser) {
clearRefreshTokenCookie(event);
return forbiddenResponse(event, 'Username or password is incorrect.');
}
const accessToken = generateAccessToken(findUser);
const refreshToken = generateRefreshToken(findUser);
setRefreshTokenCookie(event, refreshToken);
return useResponseSuccess({
...findUser,
accessToken,
});
});

View File

@@ -1,17 +0,0 @@
import { defineEventHandler } from 'h3';
import {
clearRefreshTokenCookie,
getRefreshTokenFromCookie,
} from '~/utils/cookie-utils';
import { useResponseSuccess } from '~/utils/response';
export default defineEventHandler(async (event) => {
const refreshToken = getRefreshTokenFromCookie(event);
if (!refreshToken) {
return useResponseSuccess('');
}
clearRefreshTokenCookie(event);
return useResponseSuccess('');
});

View File

@@ -1,35 +0,0 @@
import { defineEventHandler } from 'h3';
import {
clearRefreshTokenCookie,
getRefreshTokenFromCookie,
setRefreshTokenCookie,
} from '~/utils/cookie-utils';
import { generateAccessToken, verifyRefreshToken } from '~/utils/jwt-utils';
import { MOCK_USERS } from '~/utils/mock-data';
import { forbiddenResponse } from '~/utils/response';
export default defineEventHandler(async (event) => {
const refreshToken = getRefreshTokenFromCookie(event);
if (!refreshToken) {
return forbiddenResponse(event);
}
clearRefreshTokenCookie(event);
const userinfo = verifyRefreshToken(refreshToken);
if (!userinfo) {
return forbiddenResponse(event);
}
const findUser = MOCK_USERS.find(
(item) => item.username === userinfo.username,
);
if (!findUser) {
return forbiddenResponse(event);
}
const accessToken = generateAccessToken(findUser);
setRefreshTokenCookie(event, refreshToken);
return accessToken;
});

View File

@@ -1,32 +0,0 @@
import { eventHandler, setHeader } from 'h3';
import { verifyAccessToken } from '~/utils/jwt-utils';
import { unAuthorizedResponse } from '~/utils/response';
export default eventHandler(async (event) => {
const userinfo = verifyAccessToken(event);
if (!userinfo) {
return unAuthorizedResponse(event);
}
const data = `
{
"code": 0,
"message": "success",
"data": [
{
"id": 123456789012345678901234567890123456789012345678901234567890,
"name": "John Doe",
"age": 30,
"email": "john-doe@demo.com"
},
{
"id": 987654321098765432109876543210987654321098765432109876543210,
"name": "Jane Smith",
"age": 25,
"email": "jane@demo.com"
}
]
}
`;
setHeader(event, 'Content-Type', 'application/json');
return data;
});

View File

@@ -1,15 +0,0 @@
import { eventHandler } from 'h3';
import { verifyAccessToken } from '~/utils/jwt-utils';
import { MOCK_MENUS } from '~/utils/mock-data';
import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';
export default eventHandler(async (event) => {
const userinfo = verifyAccessToken(event);
if (!userinfo) {
return unAuthorizedResponse(event);
}
const menus =
MOCK_MENUS.find((item) => item.username === userinfo.username)?.menus ?? [];
return useResponseSuccess(menus);
});

View File

@@ -1,8 +0,0 @@
import { eventHandler, getQuery, setResponseStatus } from 'h3';
import { useResponseError } from '~/utils/response';
export default eventHandler((event) => {
const { status } = getQuery(event);
setResponseStatus(event, Number(status));
return useResponseError(`${status}`);
});

View File

@@ -1,16 +0,0 @@
import { eventHandler } from 'h3';
import { verifyAccessToken } from '~/utils/jwt-utils';
import {
sleep,
unAuthorizedResponse,
useResponseSuccess,
} from '~/utils/response';
export default eventHandler(async (event) => {
const userinfo = verifyAccessToken(event);
if (!userinfo) {
return unAuthorizedResponse(event);
}
await sleep(600);
return useResponseSuccess(null);
});

View File

@@ -1,16 +0,0 @@
import { eventHandler } from 'h3';
import { verifyAccessToken } from '~/utils/jwt-utils';
import {
sleep,
unAuthorizedResponse,
useResponseSuccess,
} from '~/utils/response';
export default eventHandler(async (event) => {
const userinfo = verifyAccessToken(event);
if (!userinfo) {
return unAuthorizedResponse(event);
}
await sleep(1000);
return useResponseSuccess(null);
});

View File

@@ -1,16 +0,0 @@
import { eventHandler } from 'h3';
import { verifyAccessToken } from '~/utils/jwt-utils';
import {
sleep,
unAuthorizedResponse,
useResponseSuccess,
} from '~/utils/response';
export default eventHandler(async (event) => {
const userinfo = verifyAccessToken(event);
if (!userinfo) {
return unAuthorizedResponse(event);
}
await sleep(2000);
return useResponseSuccess(null);
});

View File

@@ -1,62 +0,0 @@
import { faker } from '@faker-js/faker';
import { eventHandler } from 'h3';
import { verifyAccessToken } from '~/utils/jwt-utils';
import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';
const formatterCN = new Intl.DateTimeFormat('zh-CN', {
timeZone: 'Asia/Shanghai',
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
});
function generateMockDataList(count: number) {
const dataList = [];
for (let i = 0; i < count; i++) {
const dataItem: Record<string, any> = {
id: faker.string.uuid(),
pid: 0,
name: faker.commerce.department(),
status: faker.helpers.arrayElement([0, 1]),
createTime: formatterCN.format(
faker.date.between({ from: '2021-01-01', to: '2022-12-31' }),
),
remark: faker.lorem.sentence(),
};
if (faker.datatype.boolean()) {
dataItem.children = Array.from(
{ length: faker.number.int({ min: 1, max: 5 }) },
() => ({
id: faker.string.uuid(),
pid: dataItem.id,
name: faker.commerce.department(),
status: faker.helpers.arrayElement([0, 1]),
createTime: formatterCN.format(
faker.date.between({ from: '2023-01-01', to: '2023-12-31' }),
),
remark: faker.lorem.sentence(),
}),
);
}
dataList.push(dataItem);
}
return dataList;
}
const mockData = generateMockDataList(10);
export default eventHandler(async (event) => {
const userinfo = verifyAccessToken(event);
if (!userinfo) {
return unAuthorizedResponse(event);
}
const listData = structuredClone(mockData);
return useResponseSuccess(listData);
});

View File

@@ -1,13 +0,0 @@
import { eventHandler } from 'h3';
import { verifyAccessToken } from '~/utils/jwt-utils';
import { MOCK_MENU_LIST } from '~/utils/mock-data';
import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';
export default eventHandler(async (event) => {
const userinfo = verifyAccessToken(event);
if (!userinfo) {
return unAuthorizedResponse(event);
}
return useResponseSuccess(MOCK_MENU_LIST);
});

View File

@@ -1,29 +0,0 @@
import { eventHandler, getQuery } from 'h3';
import { verifyAccessToken } from '~/utils/jwt-utils';
import { MOCK_MENU_LIST } from '~/utils/mock-data';
import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';
const namesMap: Record<string, any> = {};
function getNames(menus: any[]) {
menus.forEach((menu) => {
namesMap[menu.name] = String(menu.id);
if (menu.children) {
getNames(menu.children);
}
});
}
getNames(MOCK_MENU_LIST);
export default eventHandler(async (event) => {
const userinfo = verifyAccessToken(event);
if (!userinfo) {
return unAuthorizedResponse(event);
}
const { id, name } = getQuery(event);
return (name as string) in namesMap &&
(!id || namesMap[name as string] !== String(id))
? useResponseSuccess(true)
: useResponseSuccess(false);
});

View File

@@ -1,29 +0,0 @@
import { eventHandler, getQuery } from 'h3';
import { verifyAccessToken } from '~/utils/jwt-utils';
import { MOCK_MENU_LIST } from '~/utils/mock-data';
import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';
const pathMap: Record<string, any> = { '/': 0 };
function getPaths(menus: any[]) {
menus.forEach((menu) => {
pathMap[menu.path] = String(menu.id);
if (menu.children) {
getPaths(menu.children);
}
});
}
getPaths(MOCK_MENU_LIST);
export default eventHandler(async (event) => {
const userinfo = verifyAccessToken(event);
if (!userinfo) {
return unAuthorizedResponse(event);
}
const { id, path } = getQuery(event);
return (path as string) in pathMap &&
(!id || pathMap[path as string] !== String(id))
? useResponseSuccess(true)
: useResponseSuccess(false);
});

View File

@@ -1,84 +0,0 @@
import { faker } from '@faker-js/faker';
import { eventHandler, getQuery } from 'h3';
import { verifyAccessToken } from '~/utils/jwt-utils';
import { getMenuIds, MOCK_MENU_LIST } from '~/utils/mock-data';
import { unAuthorizedResponse, usePageResponseSuccess } from '~/utils/response';
const formatterCN = new Intl.DateTimeFormat('zh-CN', {
timeZone: 'Asia/Shanghai',
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
});
const menuIds = getMenuIds(MOCK_MENU_LIST);
function generateMockDataList(count: number) {
const dataList = [];
for (let i = 0; i < count; i++) {
const dataItem: Record<string, any> = {
id: faker.string.uuid(),
name: faker.commerce.product(),
status: faker.helpers.arrayElement([0, 1]),
createTime: formatterCN.format(
faker.date.between({ from: '2022-01-01', to: '2025-01-01' }),
),
permissions: faker.helpers.arrayElements(menuIds),
remark: faker.lorem.sentence(),
};
dataList.push(dataItem);
}
return dataList;
}
const mockData = generateMockDataList(100);
export default eventHandler(async (event) => {
const userinfo = verifyAccessToken(event);
if (!userinfo) {
return unAuthorizedResponse(event);
}
const {
page = 1,
pageSize = 20,
name,
id,
remark,
startTime,
endTime,
status,
} = getQuery(event);
let listData = structuredClone(mockData);
if (name) {
listData = listData.filter((item) =>
item.name.toLowerCase().includes(String(name).toLowerCase()),
);
}
if (id) {
listData = listData.filter((item) =>
item.id.toLowerCase().includes(String(id).toLowerCase()),
);
}
if (remark) {
listData = listData.filter((item) =>
item.remark?.toLowerCase()?.includes(String(remark).toLowerCase()),
);
}
if (startTime) {
listData = listData.filter((item) => item.createTime >= startTime);
}
if (endTime) {
listData = listData.filter((item) => item.createTime <= endTime);
}
if (['0', '1'].includes(status as string)) {
listData = listData.filter((item) => item.status === Number(status));
}
return usePageResponseSuccess(page as string, pageSize as string, listData);
});

View File

@@ -1,117 +0,0 @@
import { faker } from '@faker-js/faker';
import { eventHandler, getQuery } from 'h3';
import { verifyAccessToken } from '~/utils/jwt-utils';
import {
sleep,
unAuthorizedResponse,
usePageResponseSuccess,
} from '~/utils/response';
function generateMockDataList(count: number) {
const dataList = [];
for (let i = 0; i < count; i++) {
const dataItem = {
id: faker.string.uuid(),
imageUrl: faker.image.avatar(),
imageUrl2: faker.image.avatar(),
open: faker.datatype.boolean(),
status: faker.helpers.arrayElement(['success', 'error', 'warning']),
productName: faker.commerce.productName(),
price: faker.commerce.price(),
currency: faker.finance.currencyCode(),
quantity: faker.number.int({ min: 1, max: 100 }),
available: faker.datatype.boolean(),
category: faker.commerce.department(),
releaseDate: faker.date.past(),
rating: faker.number.float({ min: 1, max: 5 }),
description: faker.commerce.productDescription(),
weight: faker.number.float({ min: 0.1, max: 10 }),
color: faker.color.human(),
inProduction: faker.datatype.boolean(),
tags: Array.from({ length: 3 }, () => faker.commerce.productAdjective()),
};
dataList.push(dataItem);
}
return dataList;
}
const mockData = generateMockDataList(100);
export default eventHandler(async (event) => {
const userinfo = verifyAccessToken(event);
if (!userinfo) {
return unAuthorizedResponse(event);
}
await sleep(600);
const { page, pageSize, sortBy, sortOrder } = getQuery(event);
// 规范化分页参数,处理 string[]
const pageRaw = Array.isArray(page) ? page[0] : page;
const pageSizeRaw = Array.isArray(pageSize) ? pageSize[0] : pageSize;
const pageNumber = Math.max(
1,
Number.parseInt(String(pageRaw ?? '1'), 10) || 1,
);
const pageSizeNumber = Math.min(
100,
Math.max(1, Number.parseInt(String(pageSizeRaw ?? '10'), 10) || 10),
);
const listData = structuredClone(mockData);
// 规范化 query 入参,兼容 string[]
const sortKeyRaw = Array.isArray(sortBy) ? sortBy[0] : sortBy;
const sortOrderRaw = Array.isArray(sortOrder) ? sortOrder[0] : sortOrder;
// 检查 sortBy 是否是 listData 元素的合法属性键
if (
typeof sortKeyRaw === 'string' &&
listData[0] &&
Object.prototype.hasOwnProperty.call(listData[0], sortKeyRaw)
) {
// 定义数组元素的类型
type ItemType = (typeof listData)[0];
const sortKey = sortKeyRaw as keyof ItemType; // 将 sortBy 断言为合法键
const isDesc = sortOrderRaw === 'desc';
listData.sort((a, b) => {
const aValue = a[sortKey] as unknown;
const bValue = b[sortKey] as unknown;
let result = 0;
if (typeof aValue === 'number' && typeof bValue === 'number') {
result = aValue - bValue;
} else if (aValue instanceof Date && bValue instanceof Date) {
result = aValue.getTime() - bValue.getTime();
} else if (typeof aValue === 'boolean' && typeof bValue === 'boolean') {
if (aValue === bValue) {
result = 0;
} else {
result = aValue ? 1 : -1;
}
} else {
const aStr = String(aValue);
const bStr = String(bValue);
const aNum = Number(aStr);
const bNum = Number(bStr);
result =
Number.isFinite(aNum) && Number.isFinite(bNum)
? aNum - bNum
: aStr.localeCompare(bStr, undefined, {
numeric: true,
sensitivity: 'base',
});
}
return isDesc ? -result : result;
});
}
return usePageResponseSuccess(
String(pageNumber),
String(pageSizeNumber),
listData,
);
});

View File

@@ -1,3 +0,0 @@
import { defineEventHandler } from 'h3';
export default defineEventHandler(() => 'Test get handler');

View File

@@ -1,3 +0,0 @@
import { defineEventHandler } from 'h3';
export default defineEventHandler(() => 'Test post handler');

View File

@@ -1,12 +0,0 @@
import { eventHandler } from 'h3';
import { verifyAccessToken } from '~/utils/jwt-utils';
import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';
import { getTimezone } from '~/utils/timezone-utils';
export default eventHandler((event) => {
const userinfo = verifyAccessToken(event);
if (!userinfo) {
return unAuthorizedResponse(event);
}
return useResponseSuccess(getTimezone());
});

View File

@@ -1,11 +0,0 @@
import { eventHandler } from 'h3';
import { TIME_ZONE_OPTIONS } from '~/utils/mock-data';
import { useResponseSuccess } from '~/utils/response';
export default eventHandler(() => {
const data = TIME_ZONE_OPTIONS.map((o) => ({
label: `${o.timezone} (GMT${o.offset >= 0 ? `+${o.offset}` : o.offset})`,
value: o.timezone,
}));
return useResponseSuccess(data);
});

View File

@@ -1,22 +0,0 @@
import { eventHandler, readBody } from 'h3';
import { verifyAccessToken } from '~/utils/jwt-utils';
import { TIME_ZONE_OPTIONS } from '~/utils/mock-data';
import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';
import { setTimezone } from '~/utils/timezone-utils';
export default eventHandler(async (event) => {
const userinfo = verifyAccessToken(event);
if (!userinfo) {
return unAuthorizedResponse(event);
}
const body = await readBody<{ timezone?: unknown }>(event);
const timezone =
typeof body?.timezone === 'string' ? body.timezone : undefined;
const allowed = TIME_ZONE_OPTIONS.some((o) => o.timezone === timezone);
if (!timezone || !allowed) {
setResponseStatus(event, 400);
return useResponseError('Bad Request', 'Invalid timezone');
}
setTimezone(timezone);
return useResponseSuccess({});
});

View File

@@ -1,14 +0,0 @@
import { eventHandler } from 'h3';
import { verifyAccessToken } from '~/utils/jwt-utils';
import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';
export default eventHandler((event) => {
const userinfo = verifyAccessToken(event);
if (!userinfo) {
return unAuthorizedResponse(event);
}
return useResponseSuccess({
url: 'https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-v1.webp',
});
// return useResponseError("test")
});

View File

@@ -1,11 +0,0 @@
import { eventHandler } from 'h3';
import { verifyAccessToken } from '~/utils/jwt-utils';
import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';
export default eventHandler((event) => {
const userinfo = verifyAccessToken(event);
if (!userinfo) {
return unAuthorizedResponse(event);
}
return useResponseSuccess(userinfo);
});

View File

@@ -1,7 +0,0 @@
import type { NitroErrorHandler } from 'nitropack';
const errorHandler: NitroErrorHandler = function (error, event) {
event.node.res.end(`[Error Handler] ${error.stack}`);
};
export default errorHandler;

View File

@@ -1,20 +0,0 @@
import { defineEventHandler } from 'h3';
import { forbiddenResponse, sleep } from '~/utils/response';
export default defineEventHandler(async (event) => {
event.node.res.setHeader(
'Access-Control-Allow-Origin',
event.headers.get('Origin') ?? '*',
);
if (event.method === 'OPTIONS') {
event.node.res.statusCode = 204;
event.node.res.statusMessage = 'No Content.';
return 'OK';
} else if (
['DELETE', 'PATCH', 'POST', 'PUT'].includes(event.method) &&
event.path.startsWith('/api/system/')
) {
await sleep(Math.floor(Math.random() * 2000));
return forbiddenResponse(event, '演示环境,禁止修改');
}
});

View File

@@ -1,20 +0,0 @@
import errorHandler from './error';
process.env.COMPATIBILITY_DATE = new Date().toISOString();
export default defineNitroConfig({
devErrorHandler: errorHandler,
errorHandler: '~/error',
routeRules: {
'/api/**': {
cors: true,
headers: {
'Access-Control-Allow-Credentials': 'true',
'Access-Control-Allow-Headers':
'Accept, Authorization, Content-Length, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, X-CSRF-TOKEN, X-Requested-With',
'Access-Control-Allow-Methods': 'GET,HEAD,PUT,PATCH,POST,DELETE',
'Access-Control-Allow-Origin': '*',
'Access-Control-Expose-Headers': '*',
},
},
},
});

View File

@@ -1,21 +0,0 @@
{
"name": "@vben/backend-mock",
"version": "0.0.1",
"description": "",
"private": true,
"license": "MIT",
"author": "",
"scripts": {
"build": "nitro build",
"start": "nitro dev"
},
"dependencies": {
"@faker-js/faker": "catalog:",
"jsonwebtoken": "catalog:",
"nitropack": "catalog:"
},
"devDependencies": {
"@types/jsonwebtoken": "catalog:",
"h3": "catalog:"
}
}

View File

@@ -1,15 +0,0 @@
import { defineEventHandler } from 'h3';
export default defineEventHandler(() => {
return `
<h1>Hello Vben Admin</h1>
<h2>Mock service is starting</h2>
<ul>
<li><a href="/api/user">/api/user/info</a></li>
<li><a href="/api/menu">/api/menu/all</a></li>
<li><a href="/api/auth/codes">/api/auth/codes</a></li>
<li><a href="/api/auth/login">/api/auth/login</a></li>
<li><a href="/api/upload">/api/upload</a></li>
</ul>
`;
});

View File

@@ -1,4 +0,0 @@
{
"extends": "./tsconfig.json",
"exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
}

View File

@@ -1,3 +0,0 @@
{
"extends": "./.nitro/types/tsconfig.json"
}

View File

@@ -1,28 +0,0 @@
import type { EventHandlerRequest, H3Event } from 'h3';
import { deleteCookie, getCookie, setCookie } from 'h3';
export function clearRefreshTokenCookie(event: H3Event<EventHandlerRequest>) {
deleteCookie(event, 'jwt', {
httpOnly: true,
sameSite: 'none',
secure: true,
});
}
export function setRefreshTokenCookie(
event: H3Event<EventHandlerRequest>,
refreshToken: string,
) {
setCookie(event, 'jwt', refreshToken, {
httpOnly: true,
maxAge: 24 * 60 * 60, // unit: seconds
sameSite: 'none',
secure: true,
});
}
export function getRefreshTokenFromCookie(event: H3Event<EventHandlerRequest>) {
const refreshToken = getCookie(event, 'jwt');
return refreshToken;
}

View File

@@ -1,77 +0,0 @@
import type { EventHandlerRequest, H3Event } from 'h3';
import type { UserInfo } from './mock-data';
import { getHeader } from 'h3';
import jwt from 'jsonwebtoken';
import { MOCK_USERS } from './mock-data';
// TODO: Replace with your own secret key
const ACCESS_TOKEN_SECRET = 'access_token_secret';
const REFRESH_TOKEN_SECRET = 'refresh_token_secret';
export interface UserPayload extends UserInfo {
iat: number;
exp: number;
}
export function generateAccessToken(user: UserInfo) {
return jwt.sign(user, ACCESS_TOKEN_SECRET, { expiresIn: '7d' });
}
export function generateRefreshToken(user: UserInfo) {
return jwt.sign(user, REFRESH_TOKEN_SECRET, {
expiresIn: '30d',
});
}
export function verifyAccessToken(
event: H3Event<EventHandlerRequest>,
): null | Omit<UserInfo, 'password'> {
const authHeader = getHeader(event, 'Authorization');
if (!authHeader?.startsWith('Bearer')) {
return null;
}
const tokenParts = authHeader.split(' ');
if (tokenParts.length !== 2) {
return null;
}
const token = tokenParts[1] as string;
try {
const decoded = jwt.verify(
token,
ACCESS_TOKEN_SECRET,
) as unknown as UserPayload;
const username = decoded.username;
const user = MOCK_USERS.find((item) => item.username === username);
if (!user) {
return null;
}
const { password: _pwd, ...userinfo } = user;
return userinfo;
} catch {
return null;
}
}
export function verifyRefreshToken(
token: string,
): null | Omit<UserInfo, 'password'> {
try {
const decoded = jwt.verify(token, REFRESH_TOKEN_SECRET) as UserPayload;
const username = decoded.username;
const user = MOCK_USERS.find(
(item) => item.username === username,
) as UserInfo;
if (!user) {
return null;
}
const { password: _pwd, ...userinfo } = user;
return userinfo;
} catch {
return null;
}
}

View File

@@ -1,421 +0,0 @@
export interface UserInfo {
id: number;
password: string;
realName: string;
roles: string[];
username: string;
homePath?: string;
}
export interface TimezoneOption {
offset: number;
timezone: string;
}
export const MOCK_USERS: UserInfo[] = [
{
id: 0,
password: '123456',
realName: 'Vben',
roles: ['super'],
username: 'vben',
},
{
id: 1,
password: '123456',
realName: 'Admin',
roles: ['admin'],
username: 'admin',
homePath: '/workspace',
},
{
id: 2,
password: '123456',
realName: 'Jack',
roles: ['user'],
username: 'jack',
homePath: '/analytics',
},
];
export const MOCK_CODES = [
// super
{
codes: ['AC_100100', 'AC_100110', 'AC_100120', 'AC_100010'],
username: 'vben',
},
{
// admin
codes: ['AC_100010', 'AC_100020', 'AC_100030'],
username: 'admin',
},
{
// user
codes: ['AC_1000001', 'AC_1000002'],
username: 'jack',
},
];
const dashboardMenus = [
{
meta: {
order: -1,
title: 'page.dashboard.title',
},
name: 'Dashboard',
path: '/dashboard',
redirect: '/analytics',
children: [
{
name: 'Analytics',
path: '/analytics',
component: '/dashboard/analytics/index',
meta: {
affixTab: true,
title: 'page.dashboard.analytics',
},
},
{
name: 'Workspace',
path: '/workspace',
component: '/dashboard/workspace/index',
meta: {
title: 'page.dashboard.workspace',
},
},
],
},
];
const createDemosMenus = (role: 'admin' | 'super' | 'user') => {
const roleWithMenus = {
admin: {
component: '/demos/access/admin-visible',
meta: {
icon: 'mdi:button-cursor',
title: 'demos.access.adminVisible',
},
name: 'AccessAdminVisibleDemo',
path: '/demos/access/admin-visible',
},
super: {
component: '/demos/access/super-visible',
meta: {
icon: 'mdi:button-cursor',
title: 'demos.access.superVisible',
},
name: 'AccessSuperVisibleDemo',
path: '/demos/access/super-visible',
},
user: {
component: '/demos/access/user-visible',
meta: {
icon: 'mdi:button-cursor',
title: 'demos.access.userVisible',
},
name: 'AccessUserVisibleDemo',
path: '/demos/access/user-visible',
},
};
return [
{
meta: {
icon: 'ic:baseline-view-in-ar',
keepAlive: true,
order: 1000,
title: 'demos.title',
},
name: 'Demos',
path: '/demos',
redirect: '/demos/access',
children: [
{
name: 'AccessDemos',
path: '/demosaccess',
meta: {
icon: 'mdi:cloud-key-outline',
title: 'demos.access.backendPermissions',
},
redirect: '/demos/access/page-control',
children: [
{
name: 'AccessPageControlDemo',
path: '/demos/access/page-control',
component: '/demos/access/index',
meta: {
icon: 'mdi:page-previous-outline',
title: 'demos.access.pageAccess',
},
},
{
name: 'AccessButtonControlDemo',
path: '/demos/access/button-control',
component: '/demos/access/button-control',
meta: {
icon: 'mdi:button-cursor',
title: 'demos.access.buttonControl',
},
},
{
name: 'AccessMenuVisible403Demo',
path: '/demos/access/menu-visible-403',
component: '/demos/access/menu-visible-403',
meta: {
authority: ['no-body'],
icon: 'mdi:button-cursor',
menuVisibleWithForbidden: true,
title: 'demos.access.menuVisible403',
},
},
roleWithMenus[role],
],
},
],
},
];
};
export const MOCK_MENUS = [
{
menus: [...dashboardMenus, ...createDemosMenus('super')],
username: 'vben',
},
{
menus: [...dashboardMenus, ...createDemosMenus('admin')],
username: 'admin',
},
{
menus: [...dashboardMenus, ...createDemosMenus('user')],
username: 'jack',
},
];
export const MOCK_MENU_LIST = [
{
id: 1,
name: 'Workspace',
status: 1,
type: 'menu',
icon: 'mdi:dashboard',
path: '/workspace',
component: '/dashboard/workspace/index',
meta: {
icon: 'carbon:workspace',
title: 'page.dashboard.workspace',
affixTab: true,
order: 0,
},
},
{
id: 2,
meta: {
icon: 'carbon:settings',
order: 9997,
title: 'system.title',
badge: 'new',
badgeType: 'normal',
badgeVariants: 'primary',
},
status: 1,
type: 'catalog',
name: 'System',
path: '/system',
children: [
{
id: 201,
pid: 2,
path: '/system/menu',
name: 'SystemMenu',
authCode: 'System:Menu:List',
status: 1,
type: 'menu',
meta: {
icon: 'carbon:menu',
title: 'system.menu.title',
},
component: '/system/menu/list',
children: [
{
id: 20_101,
pid: 201,
name: 'SystemMenuCreate',
status: 1,
type: 'button',
authCode: 'System:Menu:Create',
meta: { title: 'common.create' },
},
{
id: 20_102,
pid: 201,
name: 'SystemMenuEdit',
status: 1,
type: 'button',
authCode: 'System:Menu:Edit',
meta: { title: 'common.edit' },
},
{
id: 20_103,
pid: 201,
name: 'SystemMenuDelete',
status: 1,
type: 'button',
authCode: 'System:Menu:Delete',
meta: { title: 'common.delete' },
},
],
},
{
id: 202,
pid: 2,
path: '/system/dept',
name: 'SystemDept',
status: 1,
type: 'menu',
authCode: 'System:Dept:List',
meta: {
icon: 'carbon:container-services',
title: 'system.dept.title',
},
component: '/system/dept/list',
children: [
{
id: 20_401,
pid: 202,
name: 'SystemDeptCreate',
status: 1,
type: 'button',
authCode: 'System:Dept:Create',
meta: { title: 'common.create' },
},
{
id: 20_402,
pid: 202,
name: 'SystemDeptEdit',
status: 1,
type: 'button',
authCode: 'System:Dept:Edit',
meta: { title: 'common.edit' },
},
{
id: 20_403,
pid: 202,
name: 'SystemDeptDelete',
status: 1,
type: 'button',
authCode: 'System:Dept:Delete',
meta: { title: 'common.delete' },
},
],
},
],
},
{
id: 9,
meta: {
badgeType: 'dot',
order: 9998,
title: 'demos.vben.title',
icon: 'carbon:data-center',
},
name: 'Project',
path: '/vben-admin',
type: 'catalog',
status: 1,
children: [
{
id: 901,
pid: 9,
name: 'VbenDocument',
path: '/vben-admin/document',
component: 'IFrameView',
type: 'embedded',
status: 1,
meta: {
icon: 'carbon:book',
iframeSrc: 'https://doc.vben.pro',
title: 'demos.vben.document',
},
},
{
id: 902,
pid: 9,
name: 'VbenGithub',
path: '/vben-admin/github',
component: 'IFrameView',
type: 'link',
status: 1,
meta: {
icon: 'carbon:logo-github',
link: 'https://github.com/vbenjs/vue-vben-admin',
title: 'Github',
},
},
{
id: 903,
pid: 9,
name: 'VbenAntdv',
path: '/vben-admin/antdv',
component: 'IFrameView',
type: 'link',
status: 0,
meta: {
icon: 'carbon:hexagon-vertical-solid',
badgeType: 'dot',
link: 'https://ant.vben.pro',
title: 'demos.vben.antdv',
},
},
],
},
{
id: 10,
component: '_core/about/index',
type: 'menu',
status: 1,
meta: {
icon: 'lucide:copyright',
order: 9999,
title: 'demos.vben.about',
},
name: 'About',
path: '/about',
},
];
export function getMenuIds(menus: any[]) {
const ids: number[] = [];
menus.forEach((item) => {
ids.push(item.id);
if (item.children && item.children.length > 0) {
ids.push(...getMenuIds(item.children));
}
});
return ids;
}
/**
* 时区选项
*/
export const TIME_ZONE_OPTIONS: TimezoneOption[] = [
{
offset: -5,
timezone: 'America/New_York',
},
{
offset: 0,
timezone: 'Europe/London',
},
{
offset: 8,
timezone: 'Asia/Shanghai',
},
{
offset: 9,
timezone: 'Asia/Tokyo',
},
{
offset: 9,
timezone: 'Asia/Seoul',
},
];

View File

@@ -1,70 +0,0 @@
import type { EventHandlerRequest, H3Event } from 'h3';
import { setResponseStatus } from 'h3';
export function useResponseSuccess<T = any>(data: T) {
return {
code: 0,
data,
error: null,
message: 'ok',
};
}
export function usePageResponseSuccess<T = any>(
page: number | string,
pageSize: number | string,
list: T[],
{ message = 'ok' } = {},
) {
const pageData = pagination(
Number.parseInt(`${page}`),
Number.parseInt(`${pageSize}`),
list,
);
return {
...useResponseSuccess({
items: pageData,
total: list.length,
}),
message,
};
}
export function useResponseError(message: string, error: any = null) {
return {
code: -1,
data: null,
error,
message,
};
}
export function forbiddenResponse(
event: H3Event<EventHandlerRequest>,
message = 'Forbidden Exception',
) {
setResponseStatus(event, 403);
return useResponseError(message, message);
}
export function unAuthorizedResponse(event: H3Event<EventHandlerRequest>) {
setResponseStatus(event, 401);
return useResponseError('Unauthorized Exception', 'Unauthorized Exception');
}
export function sleep(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
export function pagination<T = any>(
pageNo: number,
pageSize: number,
array: T[],
): T[] {
const offset = (pageNo - 1) * Number(pageSize);
return offset + Number(pageSize) >= array.length
? array.slice(offset)
: array.slice(offset, offset + Number(pageSize));
}

View File

@@ -1,9 +0,0 @@
let mockTimeZone: null | string = null;
export const setTimezone = (timeZone: string) => {
mockTimeZone = timeZone;
};
export const getTimezone = () => {
return mockTimeZone;
};

View File

@@ -16,6 +16,7 @@ import {
erpCountInputFormatter,
erpNumberFormatter,
fenToYuan,
formatFileSize,
formatPast2,
isFunction,
isString,
@@ -354,12 +355,7 @@ setupVbenVxeTable({
// add by 星语:文件大小格式化
vxeUI.formats.add('formatFileSize', {
tableCellFormatMethod({ cellValue }, digits = 2) {
if (!cellValue) return '0 B';
const unitArr = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
const index = Math.floor(Math.log(cellValue) / Math.log(1024));
const size = cellValue / 1024 ** index;
const formattedSize = size.toFixed(digits);
return `${formattedSize} ${unitArr[index]}`;
return formatFileSize(cellValue, digits);
},
});
},

View File

@@ -15,7 +15,6 @@ export namespace AiChatConversationApi {
maxTokens: number; // 单条回复的最大 Token 数量
maxContexts: number; // 上下文的最大 Message 数量
createTime?: Date; // 创建时间
// 额外字段
systemMessage?: string; // 角色设定
modelName?: string; // 模型名字
roleAvatar?: string; // 角色头像
@@ -24,52 +23,52 @@ export namespace AiChatConversationApi {
}
}
// 获得【我的】聊天对话
/** 获得【我的】聊天对话 */
export function getChatConversationMy(id: number) {
return requestClient.get<AiChatConversationApi.ChatConversation>(
`/ai/chat/conversation/get-my?id=${id}`,
);
}
// 新增【我的】聊天对话
/** 新增【我的】聊天对话 */
export function createChatConversationMy(
data: AiChatConversationApi.ChatConversation,
) {
return requestClient.post('/ai/chat/conversation/create-my', data);
}
// 更新【我的】聊天对话
/** 更新【我的】聊天对话 */
export function updateChatConversationMy(
data: AiChatConversationApi.ChatConversation,
) {
return requestClient.put(`/ai/chat/conversation/update-my`, data);
}
// 删除【我的】聊天对话
/** 删除【我的】聊天对话 */
export function deleteChatConversationMy(id: number) {
return requestClient.delete(`/ai/chat/conversation/delete-my?id=${id}`);
}
// 删除【我的】所有对话,置顶除外
/** 删除【我的】所有对话,置顶除外 */
export function deleteChatConversationMyByUnpinned() {
return requestClient.delete(`/ai/chat/conversation/delete-by-unpinned`);
}
// 获得【我的】聊天对话列表
/** 获得【我的】聊天对话列表 */
export function getChatConversationMyList() {
return requestClient.get<AiChatConversationApi.ChatConversation[]>(
`/ai/chat/conversation/my-list`,
);
}
// 获得【我的】聊天对话列表
/** 获得【我的】聊天对话列表 */
export function getChatConversationPage(params: any) {
return requestClient.get<
PageResult<AiChatConversationApi.ChatConversation[]>
>(`/ai/chat/conversation/page`, { params });
}
// 管理员删除消息
/** 管理员删除消息 */
export function deleteChatConversationByAdmin(id: number) {
return requestClient.delete(`/ai/chat/conversation/delete-by-admin?id=${id}`);
}

View File

@@ -46,7 +46,7 @@ export namespace AiChatMessageApi {
}
}
// 消息列表
/** 消息列表 */
export function getChatMessageListByConversationId(
conversationId: null | number,
) {
@@ -55,7 +55,7 @@ export function getChatMessageListByConversationId(
);
}
// 发送 Stream 消息
/** 发送 Stream 消息 */
export function sendChatMessageStream(
conversationId: number,
content: string,
@@ -89,25 +89,27 @@ export function sendChatMessageStream(
});
}
// 删除消息
/** 删除消息 */
export function deleteChatMessage(id: number) {
return requestClient.delete(`/ai/chat/message/delete?id=${id}`);
}
// 删除指定对话的消息
/** 删除指定对话的消息 */
export function deleteByConversationId(conversationId: number) {
return requestClient.delete(
`/ai/chat/message/delete-by-conversation-id?conversationId=${conversationId}`,
);
}
// 获得消息分页
/** 获得消息分页 */
export function getChatMessagePage(params: any) {
return requestClient.get<PageResult<AiChatMessageApi.ChatMessage>>(
'/ai/chat/message/page',
{ params },
);
}
// 管理员删除消息
/** 管理员删除消息 */
export function deleteChatMessageByAdmin(id: number) {
return requestClient.delete(`/ai/chat/message/delete-by-admin?id=${id}`);
}

View File

@@ -3,14 +3,7 @@ import type { PageParam, PageResult } from '@vben/request';
import { requestClient } from '#/api/request';
export namespace AiImageApi {
export interface ImageMidjourneyButtons {
customId: string; // MJ::JOB::upsample::1::85a4b4c1-8835-46c5-a15c-aea34fad1862 动作标识
emoji: string; // 图标 emoji
label: string; // Make Variations 文本
style: number; // 样式: 2Primary、3Green
}
/** AI 绘图 */
/** 绘图 */
export interface Image {
id: number; // 编号
userId: number;
@@ -30,7 +23,14 @@ export namespace AiImageApi {
finishTime: Date; // 完成时间
}
export interface ImageDrawReq {
export interface ImageMidjourneyButtons {
customId: string; // MJ::JOB::upsample::1::85a4b4c1-8835-46c5-a15c-aea34fad1862 动作标识
emoji: string; // 图标 emoji
label: string; // Make Variations 文本
style: number; // 样式: 2Primary、3Green
}
export interface ImageDrawReqVO {
prompt: string; // 提示词
modelId: number; // 模型
style: string; // 图像生成的风格
@@ -39,7 +39,7 @@ export namespace AiImageApi {
options: object; // 绘制参数Map<String, String>
}
export interface ImageMidjourneyImagineReq {
export interface ImageMidjourneyImagineReqVO {
prompt: string; // 提示词
modelId: number; // 模型
base64Array?: string[]; // size不能为空
@@ -54,60 +54,62 @@ export namespace AiImageApi {
}
}
// 获取【我的】绘图分页
/** 获取【我的】绘图分页 */
export function getImagePageMy(params: PageParam) {
return requestClient.get<PageResult<AiImageApi.Image>>('/ai/image/my-page', {
params,
});
}
// 获取【我的】绘图记录
/** 获取【我的】绘图记录 */
export function getImageMy(id: number) {
return requestClient.get<AiImageApi.Image>(`/ai/image/get-my?id=${id}`);
}
// 获取【我的】绘图记录列表
/** 获取【我的】绘图记录列表 */
export function getImageListMyByIds(ids: number[]) {
return requestClient.get<AiImageApi.Image[]>(`/ai/image/my-list-by-ids`, {
params: { ids: ids.join(',') },
});
}
// 生成图片
export function drawImage(data: AiImageApi.ImageDrawReq) {
/** 生成图片 */
export function drawImage(data: AiImageApi.ImageDrawReqVO) {
return requestClient.post(`/ai/image/draw`, data);
}
// 删除【我的】绘画记录
/** 删除【我的】绘画记录 */
export function deleteImageMy(id: number) {
return requestClient.delete(`/ai/image/delete-my?id=${id}`);
}
// ================ midjourney 专属 ================
/** ================ midjourney 专属 ================ */
// 【Midjourney】生成图片
export function midjourneyImagine(data: AiImageApi.ImageMidjourneyImagineReq) {
/** 【Midjourney】生成图片 */
export function midjourneyImagine(
data: AiImageApi.ImageMidjourneyImagineReqVO,
) {
return requestClient.post(`/ai/image/midjourney/imagine`, data);
}
// 【Midjourney】Action 操作(二次生成图片)
/** 【Midjourney】Action 操作(二次生成图片) */
export function midjourneyAction(data: AiImageApi.ImageMidjourneyAction) {
return requestClient.post(`/ai/image/midjourney/action`, data);
}
// ================ 绘图管理 ================
/** ================ 绘图管理 ================ */
// 查询绘画分页
/** 查询绘画分页 */
export function getImagePage(params: any) {
return requestClient.get<AiImageApi.Image[]>(`/ai/image/page`, { params });
}
// 更新绘画发布状态
/** 更新绘画发布状态 */
export function updateImage(data: any) {
return requestClient.put(`/ai/image/update`, data);
}
// 删除绘画
/** 删除绘画 */
export function deleteImage(id: number) {
return requestClient.delete(`/ai/image/delete?id=${id}`);
}

View File

@@ -15,39 +15,39 @@ export namespace AiKnowledgeDocumentApi {
}
}
// 查询知识库文档分页
/** 查询知识库文档分页 */
export function getKnowledgeDocumentPage(params: PageParam) {
return requestClient.get<
PageResult<AiKnowledgeDocumentApi.KnowledgeDocument>
>('/ai/knowledge/document/page', { params });
}
// 查询知识库文档详情
/** 查询知识库文档详情 */
export function getKnowledgeDocument(id: number) {
return requestClient.get(`/ai/knowledge/document/get?id=${id}`);
}
// 新增知识库文档(单个)
/** 新增知识库文档(单个) */
export function createKnowledge(data: any) {
return requestClient.post('/ai/knowledge/document/create', data);
}
// 新增知识库文档(多个)
/** 新增知识库文档(多个) */
export function createKnowledgeDocumentList(data: any) {
return requestClient.post('/ai/knowledge/document/create-list', data);
}
// 修改知识库文档
/** 修改知识库文档 */
export function updateKnowledgeDocument(data: any) {
return requestClient.put('/ai/knowledge/document/update', data);
}
// 修改知识库文档状态
/** 修改知识库文档状态 */
export function updateKnowledgeDocumentStatus(data: any) {
return requestClient.put('/ai/knowledge/document/update-status', data);
}
// 删除知识库文档
/** 删除知识库文档 */
export function deleteKnowledgeDocument(id: number) {
return requestClient.delete(`/ai/knowledge/document/delete?id=${id}`);
}

View File

@@ -13,7 +13,7 @@ export namespace AiKnowledgeKnowledgeApi {
}
}
// 查询知识库分页
/** 查询知识库分页 */
export function getKnowledgePage(params: PageParam) {
return requestClient.get<PageResult<AiKnowledgeKnowledgeApi.Knowledge>>(
'/ai/knowledge/page',
@@ -21,29 +21,29 @@ export function getKnowledgePage(params: PageParam) {
);
}
// 查询知识库详情
/** 查询知识库详情 */
export function getKnowledge(id: number) {
return requestClient.get<AiKnowledgeKnowledgeApi.Knowledge>(
`/ai/knowledge/get?id=${id}`,
);
}
// 新增知识库
/** 新增知识库 */
export function createKnowledge(data: AiKnowledgeKnowledgeApi.Knowledge) {
return requestClient.post('/ai/knowledge/create', data);
}
// 修改知识库
/** 修改知识库 */
export function updateKnowledge(data: AiKnowledgeKnowledgeApi.Knowledge) {
return requestClient.put('/ai/knowledge/update', data);
}
// 删除知识库
/** 删除知识库 */
export function deleteKnowledge(id: number) {
return requestClient.delete(`/ai/knowledge/delete?id=${id}`);
}
// 获取知识库简单列表
/** 获取知识库简单列表 */
export function getSimpleKnowledgeList() {
return requestClient.get<AiKnowledgeKnowledgeApi.Knowledge[]>(
'/ai/knowledge/simple-list',

View File

@@ -3,7 +3,6 @@ import type { PageParam, PageResult } from '@vben/request';
import { requestClient } from '#/api/request';
export namespace AiKnowledgeSegmentApi {
// AI 知识库分段
export interface KnowledgeSegment {
id: number; // 编号
documentId: number; // 文档编号
@@ -18,7 +17,7 @@ export namespace AiKnowledgeSegmentApi {
}
}
// 查询知识库分段分页
/** 查询知识库分段分页 */
export function getKnowledgeSegmentPage(params: PageParam) {
return requestClient.get<PageResult<AiKnowledgeSegmentApi.KnowledgeSegment>>(
'/ai/knowledge/segment/page',
@@ -26,28 +25,28 @@ export function getKnowledgeSegmentPage(params: PageParam) {
);
}
// 查询知识库分段详情
/** 查询知识库分段详情 */
export function getKnowledgeSegment(id: number) {
return requestClient.get<AiKnowledgeSegmentApi.KnowledgeSegment>(
`/ai/knowledge/segment/get?id=${id}`,
);
}
// 新增知识库分段
/** 新增知识库分段 */
export function createKnowledgeSegment(
data: AiKnowledgeSegmentApi.KnowledgeSegment,
) {
return requestClient.post('/ai/knowledge/segment/create', data);
}
// 修改知识库分段
/** 修改知识库分段 */
export function updateKnowledgeSegment(
data: AiKnowledgeSegmentApi.KnowledgeSegment,
) {
return requestClient.put('/ai/knowledge/segment/update', data);
}
// 修改知识库分段状态
/** 修改知识库分段状态 */
export function updateKnowledgeSegmentStatus(id: number, status: number) {
return requestClient.put('/ai/knowledge/segment/update-status', {
id,
@@ -55,26 +54,26 @@ export function updateKnowledgeSegmentStatus(id: number, status: number) {
});
}
// 删除知识库分段
/** 删除知识库分段 */
export function deleteKnowledgeSegment(id: number) {
return requestClient.delete(`/ai/knowledge/segment/delete?id=${id}`);
}
// 切片内容
/** 切片内容 */
export function splitContent(url: string, segmentMaxTokens: number) {
return requestClient.get('/ai/knowledge/segment/split', {
params: { url, segmentMaxTokens },
});
}
// 获取文档处理列表
/** 获取文档处理列表 */
export function getKnowledgeSegmentProcessList(documentIds: number[]) {
return requestClient.get('/ai/knowledge/segment/get-process-list', {
params: { documentIds: documentIds.join(',') },
});
}
// 搜索知识库分段
/** 搜索知识库分段 */
export function searchKnowledgeSegment(params: any) {
return requestClient.get('/ai/knowledge/segment/search', {
params,

View File

@@ -8,7 +8,6 @@ const { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD);
const accessStore = useAccessStore();
export namespace AiMindmapApi {
// AI 思维导图
export interface MindMap {
id: number; // 编号
userId: number; // 用户编号
@@ -19,12 +18,12 @@ export namespace AiMindmapApi {
errorMessage: string; // 错误信息
}
// AI 思维导图生成
export interface AiMindMapGenerateReqVO {
prompt: string;
}
}
/** 生成思维导图 Stream */
export function generateMindMap({
data,
onClose,

View File

@@ -26,19 +26,19 @@ export namespace AiMusicApi {
}
}
// 查询音乐分页
/** 查询音乐分页 */
export function getMusicPage(params: PageParam) {
return requestClient.get<PageResult<AiMusicApi.Music>>(`/ai/music/page`, {
params,
});
}
// 更新音乐
/** 更新音乐 */
export function updateMusic(data: any) {
return requestClient.put('/ai/music/update', data);
}
// 删除音乐
/** 删除音乐 */
export function deleteMusic(id: number) {
return requestClient.delete(`/ai/music/delete?id=${id}`);
}

View File

@@ -36,6 +36,7 @@ export namespace AiWriteApi {
}
}
/** 写作 Stream */
export function writeStream({
data,
onClose,

View File

@@ -1,28 +1,6 @@
import { requestClient } from '#/api/request';
export namespace BpmModelApi {
/** 用户信息 TODO 这个是不是可以抽取出来定义在公共模块 */
// TODO @芋艿:一起看看。
export interface UserInfo {
id: number;
nickname: string;
avatar?: string;
deptId?: number;
deptName?: string;
}
/** 流程定义 */
export interface ProcessDefinition {
id: string;
key?: string;
version: number;
deploymentTime: number;
suspensionState: number;
formType?: number;
formCustomViewPath?: string;
formFields?: string[];
}
/** 流程模型 */
export interface Model {
id: number;
@@ -43,6 +21,27 @@ export namespace BpmModelApi {
bpmnXml: string;
startUsers?: UserInfo[];
}
/** 流程定义 */
export interface ProcessDefinition {
id: string;
key?: string;
version: number;
deploymentTime: number;
suspensionState: number;
formType?: number;
formCustomViewPath?: string;
formFields?: string[];
}
/** 用户信息 */
export interface UserInfo {
id: number;
nickname: string;
avatar?: string;
deptId?: number;
deptName?: string;
}
}
/** 模型分类信息 */

View File

@@ -11,44 +11,6 @@ import type { BpmModelApi } from '#/api/bpm/model';
import { requestClient } from '#/api/request';
export namespace BpmProcessInstanceApi {
// TODO @芋艿:一些注释缺少或者不对;
export interface Task {
id: number;
name: string;
assigneeUser?: User;
}
export interface User {
avatar: string;
deptName?: string;
id: number;
nickname: string;
}
// 审批任务信息
export interface ApprovalTaskInfo {
assigneeUser: User;
id: number;
ownerUser: User;
reason: string;
signPicUrl: string;
status: number;
}
// 审批节点信息
export interface ApprovalNodeInfo {
candidateStrategy?: BpmCandidateStrategyEnum;
candidateUsers?: User[];
endTime?: Date;
id: string;
name: string;
nodeType: BpmNodeTypeEnum;
startTime?: Date;
status: number;
processInstanceId?: string;
tasks: ApprovalTaskInfo[];
}
/** 流程实例 */
export interface ProcessInstance {
businessKey: string;
@@ -74,8 +36,23 @@ export namespace BpmProcessInstanceApi {
tasks?: BpmProcessInstanceApi.Task[];
}
// 审批详情
export interface ApprovalDetail {
/** 流程实例的任务 */
export interface Task {
id: number;
name: string;
assigneeUser?: User;
}
/** 流程实例的用户信息 */
export interface User {
id: number;
nickname: string;
avatar: string;
deptName?: string;
}
/** 审批详情 */
export interface ApprovalDetailRespVO {
activityNodes: BpmProcessInstanceApi.ApprovalNodeInfo[];
formFieldsPermission: any;
processDefinition: BpmModelApi.ProcessDefinition;
@@ -84,8 +61,32 @@ export namespace BpmProcessInstanceApi {
todoTask: BpmTaskApi.Task;
}
// 抄送流程实例
export interface Copy {
/** 审批详情的节点信息 */
export interface ApprovalNodeInfo {
candidateStrategy?: BpmCandidateStrategyEnum;
candidateUsers?: User[];
endTime?: Date;
id: string;
name: string;
nodeType: BpmNodeTypeEnum;
startTime?: Date;
status: number;
processInstanceId?: string;
tasks: ApprovalTaskInfo[];
}
/** 审批详情的节点的任务 */
export interface ApprovalTaskInfo {
id: number;
assigneeUser: User;
ownerUser: User;
reason: string;
signPicUrl: string;
status: number;
}
/** 抄送流程实例 */
export interface ProcessInstanceCopyRespVO {
activityId: string;
activityName: string;
createTime: number;
@@ -103,20 +104,17 @@ export namespace BpmProcessInstanceApi {
taskId: string;
}
/** 打印数据任务信息 */
export interface PrintTask {
description: string;
id: number;
name: string;
signPicUrl?: string;
}
/** 打印数据 */
export interface PrintData {
/** 流程实例的打印数据响应 */
export interface ProcessPrintDataRespVO {
printTemplateEnable: boolean;
printTemplateHtml?: string;
processInstance: ProcessInstance;
tasks: PrintTask[];
tasks: {
description: string;
id: number;
name: string;
signPicUrl?: string;
}[];
}
}
@@ -194,7 +192,7 @@ export async function updateProcessInstance(
/** 获取审批详情 */
export async function getApprovalDetail(params: any) {
return requestClient.get<BpmProcessInstanceApi.ApprovalDetail>(
return requestClient.get<BpmProcessInstanceApi.ApprovalDetailRespVO>(
`/bpm/process-instance/get-approval-detail`,
{ params },
);
@@ -208,14 +206,6 @@ export async function getNextApprovalNodes(params: any) {
);
}
/** 获取表单字段权限 */
export async function getFormFieldsPermission(params: any) {
return requestClient.get<BpmProcessInstanceApi.ProcessInstance>(
`/bpm/process-instance/get-form-fields-permission`,
{ params },
);
}
/** 获取流程实例 BPMN 模型视图 */
export async function getProcessInstanceBpmnModelView(id: string) {
return requestClient.get<BpmProcessInstanceApi.ProcessInstance>(
@@ -225,7 +215,7 @@ export async function getProcessInstanceBpmnModelView(id: string) {
/** 获取流程实例打印数据 */
export async function getProcessInstancePrintData(id: string) {
return requestClient.get<BpmProcessInstanceApi.PrintData>(
return requestClient.get<BpmProcessInstanceApi.ProcessPrintDataRespVO>(
`/bpm/process-instance/get-print-data?processInstanceId=${id}`,
);
}

View File

@@ -3,7 +3,7 @@ import type { PageParam, PageResult } from '@vben/request';
import { requestClient } from '#/api/request';
export namespace BpmProcessListenerApi {
/** BPM 流程监听器 */
/** 流程监听器 */
export interface ProcessListener {
id: number; // 编号
name: string; // 监听器名字

View File

@@ -5,7 +5,7 @@ import type { BpmProcessInstanceApi } from '../processInstance';
import { requestClient } from '#/api/request';
export namespace BpmTaskApi {
/** BPM 流程监听器 */
/** 流程任务 */
export interface Task {
id: number; // 编号
name: string; // 监听器名字
@@ -15,33 +15,6 @@ export namespace BpmTaskApi {
valueType: string; // 监听器值类型
processInstance?: BpmProcessInstanceApi.ProcessInstance; // 流程实例
}
// 流程任务
export interface TaskManager {
id: string; // 编号
name: string; // 任务名称
createTime: number; // 创建时间
endTime: number; // 结束时间
durationInMillis: number; // 持续时间
status: number; // 状态
reason: string; // 原因
ownerUser: any; // 负责人
assigneeUser: any; // 处理人
taskDefinitionKey: string; // 任务定义key
processInstanceId: string; // 流程实例id
processInstance: BpmProcessInstanceApi.ProcessInstance; // 流程实例
parentTaskId: any; // 父任务id
children: any; // 子任务
formId: any; // 表单id
formName: any; // 表单名称
formConf: any; // 表单配置
formFields: any; // 表单字段
formVariables: any; // 表单变量
buttonsSetting: any; // 按钮设置
signEnable: any; // 签名设置
reasonRequire: any; // 原因设置
nodeType: any; // 节点类型
}
}
/** 查询待办任务分页 */
@@ -88,51 +61,44 @@ export const getTaskListByReturn = async (id: string) => {
return await requestClient.get(`/bpm/task/list-by-return?id=${id}`);
};
/** 退回 */
/** 退回任务 */
export const returnTask = async (data: any) => {
return await requestClient.put('/bpm/task/return', data);
};
// 委派
/** 委派任务 */
export const delegateTask = async (data: any) => {
return await requestClient.put('/bpm/task/delegate', data);
};
// 转派
/** 转派任务 */
export const transferTask = async (data: any) => {
return await requestClient.put('/bpm/task/transfer', data);
};
// 加签
/** 加签任务 */
export const signCreateTask = async (data: any) => {
return await requestClient.put('/bpm/task/create-sign', data);
};
// 减签
/** 减签任务 */
export const signDeleteTask = async (data: any) => {
return await requestClient.delete('/bpm/task/delete-sign', data);
};
// 抄送
/** 抄送任务 */
export const copyTask = async (data: any) => {
return await requestClient.put('/bpm/task/copy', data);
};
// 获取我的待办任务
export const myTodoTask = async (processInstanceId: string) => {
return await requestClient.get(
`/bpm/task/my-todo?processInstanceId=${processInstanceId}`,
);
};
// 获取加签任务列表
/** 获取加签任务列表 */
export const getChildrenTaskList = async (id: string) => {
return await requestClient.get(
`/bpm/task/list-by-parent-task-id?parentTaskId=${id}`,
);
};
// 撤回任务
/** 撤回任务 */
export const withdrawTask = async (taskId: string) => {
return await requestClient.put('/bpm/task/withdraw', null, {
params: { taskId },

View File

@@ -3,7 +3,7 @@ import type { PageParam, PageResult } from '@vben/request';
import { requestClient } from '#/api/request';
export namespace BpmUserGroupApi {
/** BPM 用户组 */
/** 用户组 */
export interface UserGroup {
id: number;
name: string;

View File

@@ -5,19 +5,6 @@ import type { CrmPermissionApi } from '#/api/crm/permission';
import { requestClient } from '#/api/request';
export namespace CrmBusinessApi {
/** 商机产品信息 */
export interface BusinessProduct {
id: number;
productId: number;
productName: string;
productNo: string;
productUnit: number;
productPrice: number;
businessPrice: number;
count: number;
totalPrice: number;
}
/** 商机信息 */
export interface Business {
id: number;
@@ -49,7 +36,21 @@ export namespace CrmBusinessApi {
products?: BusinessProduct[];
}
export interface BusinessStatus {
/** 商机产品信息 */
export interface BusinessProduct {
id: number;
productId: number;
productName: string;
productNo: string;
productUnit: number;
productPrice: number;
businessPrice: number;
count: number;
totalPrice: number;
}
/** 商机更新状态请求 */
export interface BusinessUpdateStatusReqVO {
id: number;
statusId: number | undefined;
endStatus: number | undefined;
@@ -97,7 +98,9 @@ export function updateBusiness(data: CrmBusinessApi.Business) {
}
/** 修改商机状态 */
export function updateBusinessStatus(data: CrmBusinessApi.BusinessStatus) {
export function updateBusinessStatus(
data: CrmBusinessApi.BusinessUpdateStatusReqVO,
) {
return requestClient.put('/crm/business/update-status', data);
}
@@ -120,6 +123,6 @@ export function getBusinessPageByContact(params: PageParam) {
}
/** 商机转移 */
export function transferBusiness(data: CrmPermissionApi.TransferReq) {
export function transferBusiness(data: CrmPermissionApi.BusinessTransferReqVO) {
return requestClient.put('/crm/business/transfer', data);
}

View File

@@ -3,14 +3,6 @@ import type { PageParam, PageResult } from '@vben/request';
import { requestClient } from '#/api/request';
export namespace CrmBusinessStatusApi {
/** 商机状态信息 */
export interface BusinessStatusType {
[x: string]: any;
id?: number;
name: string;
percent: number;
}
/** 商机状态组信息 */
export interface BusinessStatus {
id?: number;
@@ -21,6 +13,14 @@ export namespace CrmBusinessStatusApi {
createTime?: Date;
statuses?: BusinessStatusType[];
}
/** 商机状态信息 */
export interface BusinessStatusType {
id?: number;
name: string;
percent: number;
[x: string]: any;
}
}
/** 默认商机状态 */

View File

@@ -71,7 +71,7 @@ export function exportClue(params: any) {
}
/** 线索转移 */
export function transferClue(data: CrmPermissionApi.TransferReq) {
export function transferClue(data: CrmPermissionApi.BusinessTransferReqVO) {
return requestClient.put('/crm/clue/transfer', data);
}

View File

@@ -38,13 +38,13 @@ export namespace CrmContactApi {
}
/** 联系人商机关联请求 */
export interface ContactBusinessReq {
export interface ContactBusinessReqVO {
contactId: number;
businessIds: number[];
}
/** 商机联系人关联请求 */
export interface BusinessContactReq {
export interface BusinessContactReqVO {
businessId: number;
contactIds: number[];
}
@@ -108,33 +108,33 @@ export function getSimpleContactList() {
/** 批量新增联系人商机关联 */
export function createContactBusinessList(
data: CrmContactApi.ContactBusinessReq,
data: CrmContactApi.ContactBusinessReqVO,
) {
return requestClient.post('/crm/contact/create-business-list', data);
}
/** 批量新增商机联系人关联 */
export function createBusinessContactList(
data: CrmContactApi.BusinessContactReq,
data: CrmContactApi.BusinessContactReqVO,
) {
return requestClient.post('/crm/contact/create-business-list2', data);
}
/** 解除联系人商机关联 */
export function deleteContactBusinessList(
data: CrmContactApi.ContactBusinessReq,
data: CrmContactApi.ContactBusinessReqVO,
) {
return requestClient.delete('/crm/contact/delete-business-list', { data });
}
/** 解除商机联系人关联 */
export function deleteBusinessContactList(
data: CrmContactApi.BusinessContactReq,
data: CrmContactApi.BusinessContactReqVO,
) {
return requestClient.delete('/crm/contact/delete-business-list2', { data });
}
/** 联系人转移 */
export function transferContact(data: CrmPermissionApi.TransferReq) {
export function transferContact(data: CrmPermissionApi.BusinessTransferReqVO) {
return requestClient.put('/crm/contact/transfer', data);
}

View File

@@ -5,19 +5,6 @@ import type { CrmPermissionApi } from '#/api/crm/permission';
import { requestClient } from '#/api/request';
export namespace CrmContractApi {
/** 合同产品信息 */
export interface ContractProduct {
id: number;
productId: number;
productName: string;
productNo: string;
productUnit: number;
productPrice: number;
contractPrice: number;
count: number;
totalPrice: number;
}
/** 合同信息 */
export interface Contract {
id: number;
@@ -52,6 +39,19 @@ export namespace CrmContractApi {
products?: ContractProduct[];
contactName?: string;
}
/** 合同产品信息 */
export interface ContractProduct {
id: number;
productId: number;
productName: string;
productNo: string;
productUnit: number;
productPrice: number;
contractPrice: number;
count: number;
totalPrice: number;
}
}
/** 查询合同列表 */
@@ -118,7 +118,7 @@ export function submitContract(id: number) {
}
/** 合同转移 */
export function transferContract(data: CrmPermissionApi.TransferReq) {
export function transferContract(data: CrmPermissionApi.BusinessTransferReqVO) {
return requestClient.put('/crm/contract/transfer', data);
}

View File

@@ -38,7 +38,8 @@ export namespace CrmCustomerApi {
poolDay?: number; // 距离进入公海天数
}
export interface CustomerImport {
/** 客户导入请求 */
export interface CustomerImportReqVO {
ownerUserId: number;
file: File;
updateSupport: boolean;
@@ -86,7 +87,7 @@ export function importCustomerTemplate() {
}
/** 导入客户 */
export function importCustomer(data: CrmCustomerApi.CustomerImport) {
export function importCustomer(data: CrmCustomerApi.CustomerImportReqVO) {
return requestClient.upload('/crm/customer/import', data);
}
@@ -98,7 +99,7 @@ export function getCustomerSimpleList() {
}
/** 客户转移 */
export function transferCustomer(data: CrmPermissionApi.TransferReq) {
export function transferCustomer(data: CrmPermissionApi.BusinessTransferReqVO) {
return requestClient.put('/crm/customer/transfer', data);
}

View File

@@ -3,18 +3,6 @@ import type { PageParam, PageResult } from '@vben/request';
import { requestClient } from '#/api/request';
export namespace CrmFollowUpApi {
/** 关联商机信息 */
export interface Business {
id: number;
name: string;
}
/** 关联联系人信息 */
export interface Contact {
id: number;
name: string;
}
/** 跟进记录信息 */
export interface FollowUpRecord {
id: number; // 编号
@@ -32,6 +20,18 @@ export namespace CrmFollowUpApi {
creator: string;
creatorName?: string;
}
/** 关联商机信息 */
export interface Business {
id: number;
name: string;
}
/** 关联联系人信息 */
export interface Contact {
id: number;
name: string;
}
}
/** 查询跟进记录分页 */

View File

@@ -5,12 +5,6 @@ import type { SystemOperateLogApi } from '#/api/system/operate-log';
import { requestClient } from '#/api/request';
export namespace CrmOperateLogApi {
/** 操作日志查询参数 */
export interface OperateLogQuery {
bizType: number;
bizId: number;
}
/** 操作日志信息 */
export interface OperateLog {
id: number;
@@ -22,10 +16,18 @@ export namespace CrmOperateLogApi {
creatorName?: string;
createTime: Date;
}
/** 操作日志查询请求 */
export interface OperateLogQueryReqVO {
bizType: number;
bizId: number;
}
}
/** 获得操作日志 */
export function getOperateLogPage(params: CrmOperateLogApi.OperateLogQuery) {
export function getOperateLogPage(
params: CrmOperateLogApi.OperateLogQueryReqVO,
) {
return requestClient.get<PageResult<SystemOperateLogApi.OperateLog>>(
'/crm/operate-log/page',
{ params },

View File

@@ -17,14 +17,15 @@ export namespace CrmPermissionApi {
}
/** 数据权限转移请求 */
export interface TransferReq {
export interface BusinessTransferReqVO {
id: number; // 模块编号
newOwnerUserId: number; // 新负责人的用户编号
oldOwnerPermissionLevel?: number; // 老负责人加入团队后的权限级别
toBizTypes?: number[]; // 转移客户时,需要额外有【联系人】【商机】【合同】的 checkbox 选择
}
export interface PermissionListReq {
/** 权限列表请求 */
export interface PermissionListReqVO {
bizId: number; // 模块数据编号
bizType: number; // 模块类型
}
@@ -54,7 +55,9 @@ export enum PermissionLevelEnum {
}
/** 获得数据权限列表(查询团队成员列表) */
export function getPermissionList(params: CrmPermissionApi.PermissionListReq) {
export function getPermissionList(
params: CrmPermissionApi.PermissionListReqVO,
) {
return requestClient.get<CrmPermissionApi.Permission[]>(
'/crm/permission/list',
{ params },

View File

@@ -3,14 +3,6 @@ import type { PageParam, PageResult } from '@vben/request';
import { requestClient } from '#/api/request';
export namespace CrmReceivableApi {
/** 合同信息 */
export interface Contract {
id?: number;
name?: string;
no: string;
totalPrice: number;
}
/** 回款信息 */
export interface Receivable {
id: number;
@@ -35,20 +27,17 @@ export namespace CrmReceivableApi {
updateTime: Date; // 更新时间
}
export interface ReceivablePageParam extends PageParam {
no?: string;
planId?: number;
customerId?: number;
contractId?: number;
sceneType?: number;
auditStatus?: number;
/** 合同信息 */
export interface Contract {
id?: number;
name?: string;
no: string;
totalPrice: number;
}
}
/** 查询回款列表 */
export function getReceivablePage(
params: CrmReceivableApi.ReceivablePageParam,
) {
export function getReceivablePage(params: PageParam) {
return requestClient.get<PageResult<CrmReceivableApi.Receivable>>(
'/crm/receivable/page',
{ params },
@@ -56,9 +45,7 @@ export function getReceivablePage(
}
/** 查询回款列表,基于指定客户 */
export function getReceivablePageByCustomer(
params: CrmReceivableApi.ReceivablePageParam,
) {
export function getReceivablePageByCustomer(params: PageParam) {
return requestClient.get<PageResult<CrmReceivableApi.Receivable>>(
'/crm/receivable/page-by-customer',
{ params },

View File

@@ -29,20 +29,10 @@ export namespace CrmReceivablePlanApi {
returnTime: Date;
};
}
export interface PlanPageParam extends PageParam {
customerId?: number;
contractId?: number;
contractNo?: string;
sceneType?: number;
remindType?: number;
}
}
/** 查询回款计划列表 */
export function getReceivablePlanPage(
params: CrmReceivablePlanApi.PlanPageParam,
) {
export function getReceivablePlanPage(params: PageParam) {
return requestClient.get<PageResult<CrmReceivablePlanApi.Plan>>(
'/crm/receivable-plan/page',
{ params },
@@ -50,9 +40,7 @@ export function getReceivablePlanPage(
}
/** 查询回款计划列表(按客户) */
export function getReceivablePlanPageByCustomer(
params: CrmReceivablePlanApi.PlanPageParam,
) {
export function getReceivablePlanPageByCustomer(params: PageParam) {
return requestClient.get<PageResult<CrmReceivablePlanApi.Plan>>(
'/crm/receivable-plan/page-by-customer',
{ params },

View File

@@ -1,15 +1,24 @@
import { requestClient } from '#/api/request';
export namespace CrmStatisticsCustomerApi {
/** 客户总量分析(按日期) */
export interface CustomerSummaryByDate {
/** 客户统计请求 */
export interface CustomerSummaryReqVO {
times: string[];
interval: number;
deptId: number;
userId: number;
userIds: number[];
}
/** 客户总量分析(按日期)响应 */
export interface CustomerSummaryByDateRespVO {
time: string;
customerCreateCount: number;
customerDealCount: number;
}
/** 客户总量分析(按用户) */
export interface CustomerSummaryByUser {
/** 客户总量分析(按用户)响应 */
export interface CustomerSummaryByUserRespVO {
ownerUserName: string;
customerCreateCount: number;
customerDealCount: number;
@@ -17,28 +26,28 @@ export namespace CrmStatisticsCustomerApi {
receivablePrice: number;
}
/** 客户跟进次数分析(按日期) */
export interface FollowUpSummaryByDate {
/** 客户跟进次数分析(按日期)响应 */
export interface FollowUpSummaryByDateRespVO {
time: string;
followUpRecordCount: number;
followUpCustomerCount: number;
}
/** 客户跟进次数分析(按用户) */
export interface FollowUpSummaryByUser {
/** 客户跟进次数分析(按用户)响应 */
export interface FollowUpSummaryByUserRespVO {
ownerUserName: string;
followupRecordCount: number;
followupCustomerCount: number;
}
/** 客户跟进方式统计 */
export interface FollowUpSummaryByType {
/** 客户跟进方式统计响应 */
export interface FollowUpSummaryByTypeRespVO {
followUpType: string;
followUpRecordCount: number;
}
/** 合同摘要信息 */
export interface CustomerContractSummary {
/** 合同摘要信息响应 */
export interface CustomerContractSummaryRespVO {
customerName: string;
contractName: string;
totalPrice: number;
@@ -51,54 +60,46 @@ export namespace CrmStatisticsCustomerApi {
orderDate: Date;
}
/** 客户公海分析(按日期) */
export interface PoolSummaryByDate {
/** 客户公海分析(按日期)响应 */
export interface PoolSummaryByDateRespVO {
time: string;
customerPutCount: number;
customerTakeCount: number;
}
/** 客户公海分析(按用户) */
export interface PoolSummaryByUser {
/** 客户公海分析(按用户)响应 */
export interface PoolSummaryByUserRespVO {
ownerUserName: string;
customerPutCount: number;
customerTakeCount: number;
}
/** 客户成交周期(按日期) */
export interface CustomerDealCycleByDate {
/** 客户成交周期(按日期)响应 */
export interface CustomerDealCycleByDateRespVO {
time: string;
customerDealCycle: number;
}
/** 客户成交周期(按用户) */
export interface CustomerDealCycleByUser {
/** 客户成交周期(按用户)响应 */
export interface CustomerDealCycleByUserRespVO {
ownerUserName: string;
customerDealCycle: number;
customerDealCount: number;
}
/** 客户成交周期(按地区) */
export interface CustomerDealCycleByArea {
/** 客户成交周期(按地区)响应 */
export interface CustomerDealCycleByAreaRespVO {
areaName: string;
customerDealCycle: number;
customerDealCount: number;
}
/** 客户成交周期(按产品) */
export interface CustomerDealCycleByProduct {
/** 客户成交周期(按产品)响应 */
export interface CustomerDealCycleByProductRespVO {
productName: string;
customerDealCycle: number;
customerDealCount: number;
}
export interface CustomerSummaryParams {
times: string[];
interval: number;
deptId: number;
userId: number;
userIds: number[];
}
}
export function getDatas(activeTabName: any, params: any) {
@@ -167,69 +168,63 @@ export function getChartDatas(activeTabName: any, params: any) {
/** 客户总量分析(按日期) */
export function getCustomerSummaryByDate(
params: CrmStatisticsCustomerApi.CustomerSummaryParams,
params: CrmStatisticsCustomerApi.CustomerSummaryReqVO,
) {
return requestClient.get<CrmStatisticsCustomerApi.CustomerSummaryByDate[]>(
'/crm/statistics-customer/get-customer-summary-by-date',
{ params },
);
return requestClient.get<
CrmStatisticsCustomerApi.CustomerSummaryByDateRespVO[]
>('/crm/statistics-customer/get-customer-summary-by-date', { params });
}
/** 客户总量分析(按用户) */
export function getCustomerSummaryByUser(
params: CrmStatisticsCustomerApi.CustomerSummaryParams,
params: CrmStatisticsCustomerApi.CustomerSummaryReqVO,
) {
return requestClient.get<CrmStatisticsCustomerApi.CustomerSummaryByUser[]>(
'/crm/statistics-customer/get-customer-summary-by-user',
{ params },
);
return requestClient.get<
CrmStatisticsCustomerApi.CustomerSummaryByUserRespVO[]
>('/crm/statistics-customer/get-customer-summary-by-user', { params });
}
/** 客户跟进次数分析(按日期) */
export function getFollowUpSummaryByDate(
params: CrmStatisticsCustomerApi.CustomerSummaryParams,
params: CrmStatisticsCustomerApi.CustomerSummaryReqVO,
) {
return requestClient.get<CrmStatisticsCustomerApi.FollowUpSummaryByDate[]>(
'/crm/statistics-customer/get-follow-up-summary-by-date',
{ params },
);
return requestClient.get<
CrmStatisticsCustomerApi.FollowUpSummaryByDateRespVO[]
>('/crm/statistics-customer/get-follow-up-summary-by-date', { params });
}
/** 客户跟进次数分析(按用户) */
export function getFollowUpSummaryByUser(
params: CrmStatisticsCustomerApi.CustomerSummaryParams,
params: CrmStatisticsCustomerApi.CustomerSummaryReqVO,
) {
return requestClient.get<CrmStatisticsCustomerApi.FollowUpSummaryByUser[]>(
'/crm/statistics-customer/get-follow-up-summary-by-user',
{ params },
);
return requestClient.get<
CrmStatisticsCustomerApi.FollowUpSummaryByUserRespVO[]
>('/crm/statistics-customer/get-follow-up-summary-by-user', { params });
}
/** 获取客户跟进方式统计数 */
export function getFollowUpSummaryByType(
params: CrmStatisticsCustomerApi.CustomerSummaryParams,
params: CrmStatisticsCustomerApi.CustomerSummaryReqVO,
) {
return requestClient.get<CrmStatisticsCustomerApi.FollowUpSummaryByType[]>(
'/crm/statistics-customer/get-follow-up-summary-by-type',
{ params },
);
return requestClient.get<
CrmStatisticsCustomerApi.FollowUpSummaryByTypeRespVO[]
>('/crm/statistics-customer/get-follow-up-summary-by-type', { params });
}
/** 合同摘要信息(客户转化率页面) */
export function getContractSummary(
params: CrmStatisticsCustomerApi.CustomerSummaryParams,
params: CrmStatisticsCustomerApi.CustomerSummaryReqVO,
) {
return requestClient.get<CrmStatisticsCustomerApi.CustomerContractSummary[]>(
'/crm/statistics-customer/get-contract-summary',
{ params },
);
return requestClient.get<
CrmStatisticsCustomerApi.CustomerContractSummaryRespVO[]
>('/crm/statistics-customer/get-contract-summary', { params });
}
/** 获取客户公海分析(按日期) */
export function getPoolSummaryByDate(
params: CrmStatisticsCustomerApi.CustomerSummaryParams,
params: CrmStatisticsCustomerApi.CustomerSummaryReqVO,
) {
return requestClient.get<CrmStatisticsCustomerApi.PoolSummaryByDate[]>(
return requestClient.get<CrmStatisticsCustomerApi.PoolSummaryByDateRespVO[]>(
'/crm/statistics-customer/get-pool-summary-by-date',
{ params },
);
@@ -237,9 +232,9 @@ export function getPoolSummaryByDate(
/** 获取客户公海分析(按用户) */
export function getPoolSummaryByUser(
params: CrmStatisticsCustomerApi.CustomerSummaryParams,
params: CrmStatisticsCustomerApi.CustomerSummaryReqVO,
) {
return requestClient.get<CrmStatisticsCustomerApi.PoolSummaryByUser[]>(
return requestClient.get<CrmStatisticsCustomerApi.PoolSummaryByUserRespVO[]>(
'/crm/statistics-customer/get-pool-summary-by-user',
{ params },
);
@@ -247,39 +242,36 @@ export function getPoolSummaryByUser(
/** 获取客户成交周期(按日期) */
export function getCustomerDealCycleByDate(
params: CrmStatisticsCustomerApi.CustomerSummaryParams,
params: CrmStatisticsCustomerApi.CustomerSummaryReqVO,
) {
return requestClient.get<CrmStatisticsCustomerApi.CustomerDealCycleByDate[]>(
'/crm/statistics-customer/get-customer-deal-cycle-by-date',
{ params },
);
return requestClient.get<
CrmStatisticsCustomerApi.CustomerDealCycleByDateRespVO[]
>('/crm/statistics-customer/get-customer-deal-cycle-by-date', { params });
}
/** 获取客户成交周期(按用户) */
export function getCustomerDealCycleByUser(
params: CrmStatisticsCustomerApi.CustomerSummaryParams,
params: CrmStatisticsCustomerApi.CustomerSummaryReqVO,
) {
return requestClient.get<CrmStatisticsCustomerApi.CustomerDealCycleByUser[]>(
'/crm/statistics-customer/get-customer-deal-cycle-by-user',
{ params },
);
return requestClient.get<
CrmStatisticsCustomerApi.CustomerDealCycleByUserRespVO[]
>('/crm/statistics-customer/get-customer-deal-cycle-by-user', { params });
}
/** 获取客户成交周期(按地区) */
export function getCustomerDealCycleByArea(
params: CrmStatisticsCustomerApi.CustomerSummaryParams,
params: CrmStatisticsCustomerApi.CustomerSummaryReqVO,
) {
return requestClient.get<CrmStatisticsCustomerApi.CustomerDealCycleByArea[]>(
'/crm/statistics-customer/get-customer-deal-cycle-by-area',
{ params },
);
return requestClient.get<
CrmStatisticsCustomerApi.CustomerDealCycleByAreaRespVO[]
>('/crm/statistics-customer/get-customer-deal-cycle-by-area', { params });
}
/** 获取客户成交周期(按产品) */
export function getCustomerDealCycleByProduct(
params: CrmStatisticsCustomerApi.CustomerSummaryParams,
params: CrmStatisticsCustomerApi.CustomerSummaryReqVO,
) {
return requestClient.get<
CrmStatisticsCustomerApi.CustomerDealCycleByProduct[]
CrmStatisticsCustomerApi.CustomerDealCycleByProductRespVO[]
>('/crm/statistics-customer/get-customer-deal-cycle-by-product', { params });
}

View File

@@ -3,22 +3,22 @@ import type { PageResult } from '@vben/request';
import { requestClient } from '#/api/request';
export namespace CrmStatisticsFunnelApi {
/** 销售漏斗统计数据 */
export interface FunnelSummary {
/** 销售漏斗统计数据响应 */
export interface FunnelSummaryRespVO {
customerCount: number; // 客户数
businessCount: number; // 商机数
businessWinCount: number; // 赢单数
}
/** 商机分析(按日期) */
export interface BusinessSummaryByDate {
/** 商机分析(按日期)响应 */
export interface BusinessSummaryByDateRespVO {
time: string; // 时间
businessCreateCount: number; // 商机数
totalPrice: number | string; // 商机金额
}
/** 商机转化率分析(按日期) */
export interface BusinessInversionRateSummaryByDate {
/** 商机转化率分析(按日期)响应 */
export interface BusinessInversionRateSummaryByDateRespVO {
time: string; // 时间
businessCount: number; // 商机数量
businessWinCount: number; // 赢单商机数
@@ -61,7 +61,7 @@ export function getChartDatas(activeTabName: any, params: any) {
/** 获取销售漏斗统计数据 */
export function getFunnelSummary(params: any) {
return requestClient.get<CrmStatisticsFunnelApi.FunnelSummary>(
return requestClient.get<CrmStatisticsFunnelApi.FunnelSummaryRespVO>(
'/crm/statistics-funnel/get-funnel-summary',
{ params },
);
@@ -77,16 +77,15 @@ export function getBusinessSummaryByEndStatus(params: any) {
/** 获取新增商机分析(按日期) */
export function getBusinessSummaryByDate(params: any) {
return requestClient.get<CrmStatisticsFunnelApi.BusinessSummaryByDate[]>(
'/crm/statistics-funnel/get-business-summary-by-date',
{ params },
);
return requestClient.get<
CrmStatisticsFunnelApi.BusinessSummaryByDateRespVO[]
>('/crm/statistics-funnel/get-business-summary-by-date', { params });
}
/** 获取商机转化率分析(按日期) */
export function getBusinessInversionRateSummaryByDate(params: any) {
return requestClient.get<
CrmStatisticsFunnelApi.BusinessInversionRateSummaryByDate[]
CrmStatisticsFunnelApi.BusinessInversionRateSummaryByDateRespVO[]
>('/crm/statistics-funnel/get-business-inversion-rate-summary-by-date', {
params,
});

View File

@@ -1,25 +1,27 @@
import { requestClient } from '#/api/request';
export namespace CrmStatisticsPerformanceApi {
/** 员工业绩统计 */
export interface Performance {
/** 员工业绩统计请求 */
export interface PerformanceReqVO {
times: string[];
deptId: number;
userId: number;
}
/** 员工业绩统计响应 */
export interface PerformanceRespVO {
time: string;
currentMonthCount: number;
lastMonthCount: number;
lastYearCount: number;
}
export interface PerformanceParams {
times: string[];
deptId: number;
userId: number;
}
}
/** 员工获得合同金额统计 */
export function getContractPricePerformance(
params: CrmStatisticsPerformanceApi.PerformanceParams,
params: CrmStatisticsPerformanceApi.PerformanceReqVO,
) {
return requestClient.get<CrmStatisticsPerformanceApi.Performance[]>(
return requestClient.get<CrmStatisticsPerformanceApi.PerformanceRespVO[]>(
'/crm/statistics-performance/get-contract-price-performance',
{ params },
);
@@ -27,9 +29,9 @@ export function getContractPricePerformance(
/** 员工获得回款统计 */
export function getReceivablePricePerformance(
params: CrmStatisticsPerformanceApi.PerformanceParams,
params: CrmStatisticsPerformanceApi.PerformanceReqVO,
) {
return requestClient.get<CrmStatisticsPerformanceApi.Performance[]>(
return requestClient.get<CrmStatisticsPerformanceApi.PerformanceRespVO[]>(
'/crm/statistics-performance/get-receivable-price-performance',
{ params },
);
@@ -37,9 +39,9 @@ export function getReceivablePricePerformance(
/** 员工获得签约合同数量统计 */
export function getContractCountPerformance(
params: CrmStatisticsPerformanceApi.PerformanceParams,
params: CrmStatisticsPerformanceApi.PerformanceReqVO,
) {
return requestClient.get<CrmStatisticsPerformanceApi.Performance[]>(
return requestClient.get<CrmStatisticsPerformanceApi.PerformanceRespVO[]>(
'/crm/statistics-performance/get-contract-count-performance',
{ params },
);

View File

@@ -3,33 +3,33 @@ import type { PageParam } from '@vben/request';
import { requestClient } from '#/api/request';
export namespace CrmStatisticsPortraitApi {
/** 客户基础统计信息 */
export interface CustomerBase {
/** 客户基础统计响应 */
export interface CustomerBaseRespVO {
customerCount: number;
dealCount: number;
dealPortion: number | string;
}
/** 客户行业统计信息 */
export interface CustomerIndustry extends CustomerBase {
/** 客户行业统计响应 */
export interface CustomerIndustryRespVO extends CustomerBaseRespVO {
industryId: number;
industryPortion: number | string;
}
/** 客户来源统计信息 */
export interface CustomerSource extends CustomerBase {
/** 客户来源统计响应 */
export interface CustomerSourceRespVO extends CustomerBaseRespVO {
source: number;
sourcePortion: number | string;
}
/** 客户级别统计信息 */
export interface CustomerLevel extends CustomerBase {
/** 客户级别统计响应 */
export interface CustomerLevelRespVO extends CustomerBaseRespVO {
level: number;
levelPortion: number | string;
}
/** 客户地区统计信息 */
export interface CustomerArea extends CustomerBase {
/** 客户地区统计响应 */
export interface CustomerAreaRespVO extends CustomerBaseRespVO {
areaId: number;
areaName: string;
areaPortion: number | string;
@@ -58,7 +58,7 @@ export function getDatas(activeTabName: any, params: any) {
/** 获取客户行业统计数据 */
export function getCustomerIndustry(params: PageParam) {
return requestClient.get<CrmStatisticsPortraitApi.CustomerIndustry[]>(
return requestClient.get<CrmStatisticsPortraitApi.CustomerIndustryRespVO[]>(
'/crm/statistics-portrait/get-customer-industry-summary',
{ params },
);
@@ -66,7 +66,7 @@ export function getCustomerIndustry(params: PageParam) {
/** 获取客户来源统计数据 */
export function getCustomerSource(params: PageParam) {
return requestClient.get<CrmStatisticsPortraitApi.CustomerSource[]>(
return requestClient.get<CrmStatisticsPortraitApi.CustomerSourceRespVO[]>(
'/crm/statistics-portrait/get-customer-source-summary',
{ params },
);
@@ -74,7 +74,7 @@ export function getCustomerSource(params: PageParam) {
/** 获取客户级别统计数据 */
export function getCustomerLevel(params: PageParam) {
return requestClient.get<CrmStatisticsPortraitApi.CustomerLevel[]>(
return requestClient.get<CrmStatisticsPortraitApi.CustomerLevelRespVO[]>(
'/crm/statistics-portrait/get-customer-level-summary',
{ params },
);
@@ -82,7 +82,7 @@ export function getCustomerLevel(params: PageParam) {
/** 获取客户地区统计数据 */
export function getCustomerArea(params: PageParam) {
return requestClient.get<CrmStatisticsPortraitApi.CustomerArea[]>(
return requestClient.get<CrmStatisticsPortraitApi.CustomerAreaRespVO[]>(
'/crm/statistics-portrait/get-customer-area-summary',
{ params },
);

View File

@@ -3,8 +3,8 @@ import type { PageParam } from '@vben/request';
import { requestClient } from '#/api/request';
export namespace CrmStatisticsRankApi {
/** 排行统计数据 */
export interface Rank {
/** 排行统计响应 */
export interface RankRespVO {
count: number;
nickname: string;
deptName: string;
@@ -45,7 +45,7 @@ export function getDatas(activeTabName: any, params: any) {
/** 获得合同排行榜 */
export function getContractPriceRank(params: PageParam) {
return requestClient.get<CrmStatisticsRankApi.Rank[]>(
return requestClient.get<CrmStatisticsRankApi.RankRespVO[]>(
'/crm/statistics-rank/get-contract-price-rank',
{ params },
);
@@ -53,7 +53,7 @@ export function getContractPriceRank(params: PageParam) {
/** 获得回款排行榜 */
export function getReceivablePriceRank(params: PageParam) {
return requestClient.get<CrmStatisticsRankApi.Rank[]>(
return requestClient.get<CrmStatisticsRankApi.RankRespVO[]>(
'/crm/statistics-rank/get-receivable-price-rank',
{ params },
);
@@ -61,7 +61,7 @@ export function getReceivablePriceRank(params: PageParam) {
/** 签约合同排行 */
export function getContractCountRank(params: PageParam) {
return requestClient.get<CrmStatisticsRankApi.Rank[]>(
return requestClient.get<CrmStatisticsRankApi.RankRespVO[]>(
'/crm/statistics-rank/get-contract-count-rank',
{ params },
);
@@ -69,7 +69,7 @@ export function getContractCountRank(params: PageParam) {
/** 产品销量排行 */
export function getProductSalesRank(params: PageParam) {
return requestClient.get<CrmStatisticsRankApi.Rank[]>(
return requestClient.get<CrmStatisticsRankApi.RankRespVO[]>(
'/crm/statistics-rank/get-product-sales-rank',
{ params },
);
@@ -77,7 +77,7 @@ export function getProductSalesRank(params: PageParam) {
/** 新增客户数排行 */
export function getCustomerCountRank(params: PageParam) {
return requestClient.get<CrmStatisticsRankApi.Rank[]>(
return requestClient.get<CrmStatisticsRankApi.RankRespVO[]>(
'/crm/statistics-rank/get-customer-count-rank',
{ params },
);
@@ -85,7 +85,7 @@ export function getCustomerCountRank(params: PageParam) {
/** 新增联系人数排行 */
export function getContactsCountRank(params: PageParam) {
return requestClient.get<CrmStatisticsRankApi.Rank[]>(
return requestClient.get<CrmStatisticsRankApi.RankRespVO[]>(
'/crm/statistics-rank/get-contacts-count-rank',
{ params },
);
@@ -93,7 +93,7 @@ export function getContactsCountRank(params: PageParam) {
/** 跟进次数排行 */
export function getFollowCountRank(params: PageParam) {
return requestClient.get<CrmStatisticsRankApi.Rank[]>(
return requestClient.get<CrmStatisticsRankApi.RankRespVO[]>(
'/crm/statistics-rank/get-follow-count-rank',
{ params },
);
@@ -101,7 +101,7 @@ export function getFollowCountRank(params: PageParam) {
/** 跟进客户数排行 */
export function getFollowCustomerCountRank(params: PageParam) {
return requestClient.get<CrmStatisticsRankApi.Rank[]>(
return requestClient.get<CrmStatisticsRankApi.RankRespVO[]>(
'/crm/statistics-rank/get-follow-customer-count-rank',
{ params },
);

View File

@@ -3,12 +3,6 @@ import type { PageParam, PageResult } from '@vben/request';
import { requestClient } from '#/api/request';
export namespace MallCommentApi {
export interface Property {
propertyId: number; // 属性 ID
propertyName: string; // 属性名称
valueId: number; // 属性值 ID
valueName: string; // 属性值名称
}
/** 商品评论 */
export interface Comment {
id: number; // 评论编号
@@ -32,17 +26,22 @@ export namespace MallCommentApi {
replyContent: string; // 回复内容
replyTime: Date; // 回复时间
createTime: Date; // 创建时间
skuProperties: Property[]; // SKU 属性数组
skuProperties: {
propertyId: number; // 属性 ID
propertyName: string; // 属性名称
valueId: number; // 属性值 ID
valueName: string; // 属性值名称
}[]; // SKU 属性数组
}
/** 评论可见性更新 */
export interface CommentVisibleUpdate {
/** 评论可见性更新请求 */
export interface CommentVisibleUpdateReqVO {
id: number; // 评论编号
visible: boolean; // 是否可见
}
/** 评论回复 */
export interface CommentReply {
/** 评论回复请求 */
export interface CommentReplyReqVO {
id: number; // 评论编号
replyContent: string; // 回复内容
}
@@ -70,12 +69,12 @@ export function createComment(data: MallCommentApi.Comment) {
/** 显示 / 隐藏评论 */
export function updateCommentVisible(
data: MallCommentApi.CommentVisibleUpdate,
data: MallCommentApi.CommentVisibleUpdateReqVO,
) {
return requestClient.put('/product/comment/update-visible', data);
}
/** 商家回复 */
export function replyComment(data: MallCommentApi.CommentReply) {
export function replyComment(data: MallCommentApi.CommentReplyReqVO) {
return requestClient.put('/product/comment/reply', data);
}

View File

@@ -12,9 +12,7 @@ export namespace MallHistoryApi {
}
}
/**
*
*/
/** 获得商品浏览记录分页 */
export function getBrowseHistoryPage(params: PageParam) {
return requestClient.get<PageResult<MallHistoryApi.BrowseHistory>>(
'/product/browse-history/page',

View File

@@ -17,11 +17,6 @@ export namespace MallPropertyApi {
name: string; // 名称
remark?: string; // 备注
}
/** 属性值查询参数 */
export interface PropertyValueQuery extends PageParam {
propertyId?: number; // 属性编号
}
}
/** 创建属性项 */
@@ -62,9 +57,7 @@ export function getPropertySimpleList() {
}
/** 获得属性值分页 */
export function getPropertyValuePage(
params: MallPropertyApi.PropertyValueQuery,
) {
export function getPropertyValuePage(params: PageParam) {
return requestClient.get<PageResult<MallPropertyApi.PropertyValue>>(
'/product/property/value/page',
{ params },

View File

@@ -3,39 +3,6 @@ import type { PageParam, PageResult } from '@vben/request';
import { requestClient } from '#/api/request';
export namespace MallSpuApi {
/** 商品属性 */
export interface Property {
propertyId?: number; // 属性编号
propertyName?: string; // 属性名称
valueId?: number; // 属性值编号
valueName?: string; // 属性值名称
}
/** 商品 SKU */
export interface Sku {
id?: number; // 商品 SKU 编号
name?: string; // 商品 SKU 名称
spuId?: number; // SPU 编号
properties?: Property[]; // 属性数组
price?: number | string; // 商品价格
marketPrice?: number | string; // 市场价
costPrice?: number | string; // 成本价
barCode?: string; // 商品条码
picUrl?: string; // 图片地址
stock?: number; // 库存
weight?: number; // 商品重量单位kg 千克
volume?: number; // 商品体积单位m^3 平米
firstBrokeragePrice?: number | string; // 一级分销的佣金
secondBrokeragePrice?: number | string; // 二级分销的佣金
salesCount?: number; // 商品销量
}
/** 优惠券模板 */
export interface GiveCouponTemplate {
id?: number; // 优惠券编号
name?: string; // 优惠券名称
}
/** 商品 SPU */
export interface Spu {
id?: number; // 商品编号
@@ -68,8 +35,42 @@ export namespace MallSpuApi {
browseCount?: number; // 浏览量
}
/** 商品状态更新 */
export interface StatusUpdate {
/** 商品 SKU */
export interface Sku {
id?: number; // 商品 SKU 编号
name?: string; // 商品 SKU 名称
spuId?: number; // SPU 编号
properties?: Property[]; // 属性数组
price?: number | string; // 商品价格
marketPrice?: number | string; // 市场价
costPrice?: number | string; // 成本价
barCode?: string; // 商品条码
picUrl?: string; // 图片地址
stock?: number; // 库存
weight?: number; // 商品重量单位kg 千克
volume?: number; // 商品体积单位m^3 平米
firstBrokeragePrice?: number | string; // 一级分销的佣金
secondBrokeragePrice?: number | string; // 二级分销的佣金
salesCount?: number; // 商品销量
}
/** 商品属性 */
export interface Property {
propertyId?: number; // 属性编号
propertyName?: string; // 属性名称
valueId?: number; // 属性值编号
valueName?: string; // 属性值名称
}
// TODO @puhui999这个还要么
/** 优惠券模板 */
export interface GiveCouponTemplate {
id?: number; // 优惠券编号
name?: string; // 优惠券名称
}
/** 商品状态更新请求 */
export interface SpuStatusUpdateReqVO {
id: number; // 商品编号
status: number; // 商品状态
}
@@ -98,7 +99,7 @@ export function updateSpu(data: MallSpuApi.Spu) {
}
/** 更新商品 SPU 状态 */
export function updateStatus(data: MallSpuApi.StatusUpdate) {
export function updateStatus(data: MallSpuApi.SpuStatusUpdateReqVO) {
return requestClient.put('/product/spu/update-status', data);
}

View File

@@ -33,6 +33,7 @@ export namespace MallBargainActivityApi {
stock: number; // 活动库存
}
// TODO @puhui999要不要删除
/** 扩展 SKU 配置 */
export type SkuExtension = {
productConfig: BargainProduct; // 砍价活动配置

Some files were not shown because too many files have changed in this diff Show More