Merge pull request !285 from xingyu/dev
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 348 KiB After Width: | Height: | Size: 348 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 238 KiB After Width: | Height: | Size: 238 KiB |
|
Before Width: | Height: | Size: 139 KiB After Width: | Height: | Size: 139 KiB |
|
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 69 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 201 KiB After Width: | Height: | Size: 201 KiB |
|
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 60 KiB |
|
Before Width: | Height: | Size: 196 KiB After Width: | Height: | Size: 196 KiB |
|
Before Width: | Height: | Size: 495 KiB After Width: | Height: | Size: 495 KiB |
|
Before Width: | Height: | Size: 177 KiB After Width: | Height: | Size: 177 KiB |
|
Before Width: | Height: | Size: 126 KiB After Width: | Height: | Size: 126 KiB |
89
.github/commit-convention.md
vendored
@@ -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.
|
||||
10
.github/workflows/deploy.yml
vendored
@@ -30,7 +30,7 @@ jobs:
|
||||
run: pnpm build:play
|
||||
|
||||
- name: Sync Playground files
|
||||
uses: SamKirkland/FTP-Deploy-Action@v4.3.5
|
||||
uses: SamKirkland/FTP-Deploy-Action@v4.3.6
|
||||
with:
|
||||
server: ${{ secrets.PRO_FTP_HOST }}
|
||||
username: ${{ secrets.WEB_PLAYGROUND_FTP_ACCOUNT }}
|
||||
@@ -54,7 +54,7 @@ jobs:
|
||||
run: pnpm build:docs
|
||||
|
||||
- name: Sync Docs files
|
||||
uses: SamKirkland/FTP-Deploy-Action@v4.3.5
|
||||
uses: SamKirkland/FTP-Deploy-Action@v4.3.6
|
||||
with:
|
||||
server: ${{ secrets.PRO_FTP_HOST }}
|
||||
username: ${{ secrets.WEBSITE_FTP_ACCOUNT }}
|
||||
@@ -85,7 +85,7 @@ jobs:
|
||||
run: pnpm run build:antd
|
||||
|
||||
- name: Sync files
|
||||
uses: SamKirkland/FTP-Deploy-Action@v4.3.5
|
||||
uses: SamKirkland/FTP-Deploy-Action@v4.3.6
|
||||
with:
|
||||
server: ${{ secrets.PRO_FTP_HOST }}
|
||||
username: ${{ secrets.WEB_ANTD_FTP_ACCOUNT }}
|
||||
@@ -116,7 +116,7 @@ jobs:
|
||||
run: pnpm run build:ele
|
||||
|
||||
- name: Sync files
|
||||
uses: SamKirkland/FTP-Deploy-Action@v4.3.5
|
||||
uses: SamKirkland/FTP-Deploy-Action@v4.3.6
|
||||
with:
|
||||
server: ${{ secrets.PRO_FTP_HOST }}
|
||||
username: ${{ secrets.WEB_ELE_FTP_ACCOUNT }}
|
||||
@@ -147,7 +147,7 @@ jobs:
|
||||
run: pnpm run build:naive
|
||||
|
||||
- name: Sync files
|
||||
uses: SamKirkland/FTP-Deploy-Action@v4.3.5
|
||||
uses: SamKirkland/FTP-Deploy-Action@v4.3.6
|
||||
with:
|
||||
server: ${{ secrets.PRO_FTP_HOST }}
|
||||
username: ${{ secrets.WEB_NAIVE_FTP_ACCOUNT }}
|
||||
|
||||
2
.npmrc
@@ -1,4 +1,4 @@
|
||||
registry = "https://registry.npmmirror.com"
|
||||
registry=https://registry.npmmirror.com
|
||||
public-hoist-pattern[]=lefthook
|
||||
public-hoist-pattern[]=eslint
|
||||
public-hoist-pattern[]=prettier
|
||||
|
||||
9
.vscode/launch.json
vendored
@@ -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",
|
||||
|
||||
5
.vscode/settings.json
vendored
@@ -189,10 +189,7 @@
|
||||
],
|
||||
|
||||
"github.copilot.enable": {
|
||||
"*": true,
|
||||
"markdown": true,
|
||||
"plaintext": false,
|
||||
"yaml": false
|
||||
"*": false
|
||||
},
|
||||
|
||||
"cssVariables.lookupFiles": ["packages/core/base/design/src/**/*.css"],
|
||||
|
||||
@@ -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'
|
||||
197
README.md
@@ -9,7 +9,7 @@
|
||||
|
||||
## 🐶 新手必读
|
||||
|
||||
- nodejs > 20.10.0 && pnpm > 10.14.0 (强制使用pnpm)
|
||||
- nodejs > 20.12.0 && pnpm > 10.14.0 (强制使用pnpm)
|
||||
- 演示地址【Vue3 + element-plus】:<http://dashboard-vue3.yudao.iocoder.cn>
|
||||
- 演示地址【Vue3 + vben5(ant-design-vue)】:<http://dashboard-vben.yudao.iocoder.cn>
|
||||
- 演示地址【Vue2 + element-ui】:<http://dashboard.yudao.iocoder.cn>
|
||||
@@ -21,9 +21,9 @@
|
||||
**芋道**,以开发者为中心,打造中国第一流的快速开发平台,全部开源,个人与企业可 100% 免费使用。
|
||||
|
||||
- 采用最新 [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/) 多种免费开源的中后台模版,具备如下特性:
|
||||
- 支持 [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/) 多种免费开源的中后台模版,具备如下特性:
|
||||
|
||||

|
||||

|
||||
|
||||
- **最新技术栈**:使用 Vue3、Vite6 等前端前沿技术开发
|
||||
- **TypeScript**: 应用程序级 JavaScript 的语言
|
||||
@@ -33,9 +33,9 @@
|
||||
- **组件**:二次封装了多个常用的组件
|
||||
- **示例**:内置丰富的示例
|
||||
|
||||
## 外包项目请联系【非项目需求请勿扫码,非客服,不解答项目问题】
|
||||
## [外包项目请联系【非项目需求请勿扫码,非客服,不解答项目问题】](https://www.shuduokeji.com)
|
||||
|
||||

|
||||

|
||||
|
||||
## 技术栈
|
||||
|
||||
@@ -46,12 +46,14 @@
|
||||
| [Ant Design Vue](https://www.antdv.com/) | Ant Design Vue | 4.2.6 |
|
||||
| [Element Plus](https://element-plus.org/zh-CN/) | Element Plus | 2.10.2 |
|
||||
| [Naive UI](https://www.naiveui.com/) | Naive UI | 2.42.0 |
|
||||
| [TDesign](https://tdesign.tencent.com/) | TDesign | 1.17.1 |
|
||||
| [TypeScript](https://www.typescriptlang.org/docs/) | JavaScript 超集 | 5.8.3 |
|
||||
| [pinia](https://pinia.vuejs.org/) | Vue 存储库替代 vuex5 | 3.0.3 |
|
||||
| [vueuse](https://vueuse.org/) | 常用工具集 | 13.4.0 |
|
||||
| [vue-i18n](https://kazupon.github.io/vue-i18n/zh/introduction.html/) | 国际化 | 11.1.7 |
|
||||
| [vue-router](https://router.vuejs.org/) | Vue 路由 | 4.5.1 |
|
||||
| [Tailwind CSS](https://tailwindcss.com/) | 原子 CSS | 3.4.17 |
|
||||
| [Iconify](https://iconify.design/) | 图标组件 | 5.0.0 |
|
||||
| [Iconify](https://icon-sets.iconify.design/) | 在线图标库 | 2.2.354 |
|
||||
| [TinyMCE](https://www.tiny.cloud/) | 富文本编辑器 | 6.1.0 |
|
||||
| [Echarts](https://echarts.apache.org/) | 图表库 | 5.6.0 |
|
||||
@@ -66,11 +68,11 @@
|
||||
|
||||
① Spring Boot 单体架构:<https://doc.iocoder.cn>
|
||||
|
||||

|
||||

|
||||
|
||||
② Spring Cloud 微服务架构:<https://cloud.iocoder.cn>
|
||||
|
||||

|
||||

|
||||
|
||||
## 内置功能
|
||||
|
||||
@@ -78,7 +80,7 @@
|
||||
|
||||
系统内置多种多种业务功能,可以用于快速你的业务系统:
|
||||
|
||||

|
||||

|
||||
|
||||
- 通用模块(必选):系统功能、基础设施
|
||||
- 通用模块(可选):工作流程、支付系统、数据报表、会员中心
|
||||
@@ -86,70 +88,70 @@
|
||||
|
||||
### 系统功能
|
||||
|
||||
| | 功能 | 描述 |
|
||||
| --- | --- | --- |
|
||||
| | 用户管理 | 用户是系统操作者,该功能主要完成系统用户配置 |
|
||||
| ⭐️ | 在线用户 | 当前系统中活跃用户状态监控,支持手动踢下线 |
|
||||
| | 角色管理 | 角色菜单权限分配、设置角色按机构进行数据范围权限划分 |
|
||||
| | 菜单管理 | 配置系统菜单、操作权限、按钮权限标识等,本地缓存提供性能 |
|
||||
| | 部门管理 | 配置系统组织机构(公司、部门、小组),树结构展现支持数据权限 |
|
||||
| | 岗位管理 | 配置系统用户所属担任职务 |
|
||||
| 🚀 | 租户管理 | 配置系统租户,支持 SaaS 场景下的多租户功能 |
|
||||
| 🚀 | 租户套餐 | 配置租户套餐,自定每个租户的菜单、操作、按钮的权限 |
|
||||
| | 字典管理 | 对系统中经常使用的一些较为固定的数据进行维护 |
|
||||
| 🚀 | 短信管理 | 短信渠道、短息模板、短信日志,对接阿里云、腾讯云等主流短信平台 |
|
||||
| 🚀 | 邮件管理 | 邮箱账号、邮件模版、邮件发送日志,支持所有邮件平台 |
|
||||
| 🚀 | 站内信 | 系统内的消息通知,提供站内信模版、站内信消息 |
|
||||
| 🚀 | 操作日志 | 系统正常操作日志记录和查询,集成 Swagger 生成日志内容 |
|
||||
| ⭐️ | 登录日志 | 系统登录日志记录查询,包含登录异常 |
|
||||
| 🚀 | 错误码管理 | 系统所有错误码的管理,可在线修改错误提示,无需重启服务 |
|
||||
| | 通知公告 | 系统通知公告信息发布维护 |
|
||||
| 🚀 | 敏感词 | 配置系统敏感词,支持标签分组 |
|
||||
| 🚀 | 应用管理 | 管理 SSO 单点登录的应用,支持多种 OAuth2 授权方式 |
|
||||
| 🚀 | 地区管理 | 展示省份、城市、区镇等城市信息,支持 IP 对应城市 |
|
||||
| | 功能 | 描述 |
|
||||
|----|-------|---------------------------------|
|
||||
| | 用户管理 | 用户是系统操作者,该功能主要完成系统用户配置 |
|
||||
| ⭐️ | 在线用户 | 当前系统中活跃用户状态监控,支持手动踢下线 |
|
||||
| | 角色管理 | 角色菜单权限分配、设置角色按机构进行数据范围权限划分 |
|
||||
| | 菜单管理 | 配置系统菜单、操作权限、按钮权限标识等,本地缓存提供性能 |
|
||||
| | 部门管理 | 配置系统组织机构(公司、部门、小组),树结构展现支持数据权限 |
|
||||
| | 岗位管理 | 配置系统用户所属担任职务 |
|
||||
| 🚀 | 租户管理 | 配置系统租户,支持 SaaS 场景下的多租户功能 |
|
||||
| 🚀 | 租户套餐 | 配置租户套餐,自定每个租户的菜单、操作、按钮的权限 |
|
||||
| | 字典管理 | 对系统中经常使用的一些较为固定的数据进行维护 |
|
||||
| 🚀 | 短信管理 | 短信渠道、短息模板、短信日志,对接阿里云、腾讯云等主流短信平台 |
|
||||
| 🚀 | 邮件管理 | 邮箱账号、邮件模版、邮件发送日志,支持所有邮件平台 |
|
||||
| 🚀 | 站内信 | 系统内的消息通知,提供站内信模版、站内信消息 |
|
||||
| 🚀 | 操作日志 | 系统正常操作日志记录和查询,集成 Swagger 生成日志内容 |
|
||||
| ⭐️ | 登录日志 | 系统登录日志记录查询,包含登录异常 |
|
||||
| 🚀 | 错误码管理 | 系统所有错误码的管理,可在线修改错误提示,无需重启服务 |
|
||||
| | 通知公告 | 系统通知公告信息发布维护 |
|
||||
| 🚀 | 敏感词 | 配置系统敏感词,支持标签分组 |
|
||||
| 🚀 | 应用管理 | 管理 SSO 单点登录的应用,支持多种 OAuth2 授权方式 |
|
||||
| 🚀 | 地区管理 | 展示省份、城市、区镇等城市信息,支持 IP 对应城市 |
|
||||
|
||||

|
||||

|
||||
|
||||
### 工作流程
|
||||
|
||||

|
||||

|
||||
|
||||
基于 Flowable 构建,可支持信创(国产)数据库,满足中国特色流程操作:
|
||||
|
||||
| BPMN 设计器 | 钉钉/飞书设计器 |
|
||||
| --- | --- |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|
||||
> 历经头部企业生产验证,工作流引擎须标配仿钉钉/飞书 + BPMN 双设计器!!!
|
||||
>
|
||||
> 前者支持轻量配置简单流程,后者实现复杂场景深度编排
|
||||
|
||||
| 功能列表 | 功能描述 | 是否完成 |
|
||||
| --- | --- | --- |
|
||||
| SIMPLE 设计器 | 仿钉钉/飞书设计器,支持拖拽搭建表单流程,10 分钟快速完成审批流程配置 | ✅ |
|
||||
| BPMN 设计器 | 基于 BPMN 标准开发,适配复杂业务场景,满足多层级审批及流程自动化需求 | ✅ |
|
||||
| 会签 | 同一个审批节点设置多个人(如 A、B、C 三人,三人会同时收到待办任务),需全部同意之后,审批才可到下一审批节点 | ✅ |
|
||||
| 或签 | 同一个审批节点设置多个人,任意一个人处理后,就能进入下一个节点 | ✅ |
|
||||
| 依次审批 | (顺序会签)同一个审批节点设置多个人(如 A、B、C 三人),三人按顺序依次收到待办,即 A 先审批,A 提交后 B 才能审批,需全部同意之后,审批才可到下一审批节点 | ✅ |
|
||||
| 抄送 | 将审批结果通知给抄送人,同一个审批默认排重,不重复抄送给同一人 | ✅ |
|
||||
| 驳回 | (退回)将审批重置发送给某节点,重新审批。可驳回至发起人、上一节点、任意节点 | ✅ |
|
||||
| 转办 | A 转给其 B 审批,B 审批后,进入下一节点 | ✅ |
|
||||
| 委派 | A 转给其 B 审批,B 审批后,转给 A,A 继续审批后进入下一节点 | ✅ |
|
||||
| 加签 | 允许当前审批人根据需要,自行增加当前节点的审批人,支持向前、向后加签 | ✅ |
|
||||
| 减签 | (取消加签)在当前审批人操作之前,减少审批人 | ✅ |
|
||||
| 撤销 | (取消流程)流程发起人,可以对流程进行撤销处理 | ✅ |
|
||||
| 终止 | 系统管理员,在任意节点终止流程实例 | ✅ |
|
||||
| 表单权限 | 支持拖拉拽配置表单,每个审批节点可配置只读、编辑、隐藏权限 | ✅ |
|
||||
| 超时审批 | 配置超时审批时间,超时后自动触发审批通过、不通过、驳回等操作 | ✅ |
|
||||
| 自动提醒 | 配置提醒时间,到达时间后自动触发短信、邮箱、站内信等通知提醒,支持自定义重复提醒频次 | ✅ |
|
||||
| 父子流程 | 主流程设置子流程节点,子流程节点会自动触发子流程。子流程结束后,主流程才会执行(继续往下下执行),支持同步子流程、异步子流程 | ✅ |
|
||||
| 条件分支 | (排它分支)用于在流程中实现决策,即根据条件选择一个分支执行 | ✅ |
|
||||
| 并行分支 | 允许将流程分成多条分支,不进行条件判断,所有分支都会执行 | ✅ |
|
||||
| 包容分支 | (条件分支 + 并行分支的结合体)允许基于条件选择多条分支执行,但如果没有任何一个分支满足条件,则可以选择默认分支 | ✅ |
|
||||
| 路由分支 | 根据条件选择一个分支执行(重定向到指定配置节点),也可以选择默认分支执行(继续往下执行) | ✅ |
|
||||
| 触发节点 | 执行到该节点,触发 HTTP 请求、HTTP 回调、更新数据、删除数据等 | ✅ |
|
||||
| 延迟节点 | 执行到该节点,审批等待一段时间再执行,支持固定时长、固定日期等 | ✅ |
|
||||
| 拓展设置 | 流程前置/后置通知,节点(任务)前置、后置通知,流程报表,自动审批去重,自定流程编号、标题、摘要,流程报表等 | ✅ |
|
||||
| 功能列表 | 功能描述 | 是否完成 |
|
||||
|------------|-------------------------------------------------------------------------------------|------|
|
||||
| SIMPLE 设计器 | 仿钉钉/飞书设计器,支持拖拽搭建表单流程,10 分钟快速完成审批流程配置 | ✅ |
|
||||
| BPMN 设计器 | 基于 BPMN 标准开发,适配复杂业务场景,满足多层级审批及流程自动化需求 | ✅ |
|
||||
| 会签 | 同一个审批节点设置多个人(如 A、B、C 三人,三人会同时收到待办任务),需全部同意之后,审批才可到下一审批节点 | ✅ |
|
||||
| 或签 | 同一个审批节点设置多个人,任意一个人处理后,就能进入下一个节点 | ✅ |
|
||||
| 依次审批 | (顺序会签)同一个审批节点设置多个人(如 A、B、C 三人),三人按顺序依次收到待办,即 A 先审批,A 提交后 B 才能审批,需全部同意之后,审批才可到下一审批节点 | ✅ |
|
||||
| 抄送 | 将审批结果通知给抄送人,同一个审批默认排重,不重复抄送给同一人 | ✅ |
|
||||
| 驳回 | (退回)将审批重置发送给某节点,重新审批。可驳回至发起人、上一节点、任意节点 | ✅ |
|
||||
| 转办 | A 转给其 B 审批,B 审批后,进入下一节点 | ✅ |
|
||||
| 委派 | A 转给其 B 审批,B 审批后,转给 A,A 继续审批后进入下一节点 | ✅ |
|
||||
| 加签 | 允许当前审批人根据需要,自行增加当前节点的审批人,支持向前、向后加签 | ✅ |
|
||||
| 减签 | (取消加签)在当前审批人操作之前,减少审批人 | ✅ |
|
||||
| 撤销 | (取消流程)流程发起人,可以对流程进行撤销处理 | ✅ |
|
||||
| 终止 | 系统管理员,在任意节点终止流程实例 | ✅ |
|
||||
| 表单权限 | 支持拖拉拽配置表单,每个审批节点可配置只读、编辑、隐藏权限 | ✅ |
|
||||
| 超时审批 | 配置超时审批时间,超时后自动触发审批通过、不通过、驳回等操作 | ✅ |
|
||||
| 自动提醒 | 配置提醒时间,到达时间后自动触发短信、邮箱、站内信等通知提醒,支持自定义重复提醒频次 | ✅ |
|
||||
| 父子流程 | 主流程设置子流程节点,子流程节点会自动触发子流程。子流程结束后,主流程才会执行(继续往下下执行),支持同步子流程、异步子流程 | ✅ |
|
||||
| 条件分支 | (排它分支)用于在流程中实现决策,即根据条件选择一个分支执行 | ✅ |
|
||||
| 并行分支 | 允许将流程分成多条分支,不进行条件判断,所有分支都会执行 | ✅ |
|
||||
| 包容分支 | (条件分支 + 并行分支的结合体)允许基于条件选择多条分支执行,但如果没有任何一个分支满足条件,则可以选择默认分支 | ✅ |
|
||||
| 路由分支 | 根据条件选择一个分支执行(重定向到指定配置节点),也可以选择默认分支执行(继续往下执行) | ✅ |
|
||||
| 触发节点 | 执行到该节点,触发 HTTP 请求、HTTP 回调、更新数据、删除数据等 | ✅ |
|
||||
| 延迟节点 | 执行到该节点,审批等待一段时间再执行,支持固定时长、固定日期等 | ✅ |
|
||||
| 拓展设置 | 流程前置/后置通知,节点(任务)前置、后置通知,流程报表,自动审批去重,自定流程编号、标题、摘要,流程报表等 | ✅ |
|
||||
|
||||
### 支付系统
|
||||
|
||||
@@ -163,28 +165,28 @@
|
||||
|
||||
### 基础设施
|
||||
|
||||
| | 功能 | 描述 |
|
||||
| --- | --- | --- |
|
||||
| 🚀 | 代码生成 | 前后端代码的生成(Java、Vue、SQL、单元测试),支持 CRUD 下载 |
|
||||
| 🚀 | 系统接口 | 基于 Swagger 自动生成相关的 RESTful API 接口文档 |
|
||||
| 🚀 | 数据库文档 | 基于 Screw 自动生成数据库文档,支持导出 Word、HTML、MD 格式 |
|
||||
| | 表单构建 | 拖动表单元素生成相应的 HTML 代码,支持导出 JSON、Vue 文件 |
|
||||
| 🚀 | 配置管理 | 对系统动态配置常用参数,支持 SpringBoot 加载 |
|
||||
| ⭐️ | 定时任务 | 在线(添加、修改、删除)任务调度包含执行结果日志 |
|
||||
| 🚀 | 文件服务 | 支持将文件存储到 S3(MinIO、阿里云、腾讯云、七牛云)、本地、FTP、数据库等 |
|
||||
| 🚀 | WebSocket | 提供 WebSocket 接入示例,支持一对一、一对多发送方式 |
|
||||
| 🚀 | API 日志 | 包括 RESTful API 访问日志、异常日志两部分,方便排查 API 相关的问题 |
|
||||
| | MySQL 监控 | 监视当前系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈 |
|
||||
| | Redis 监控 | 监控 Redis 数据库的使用情况,使用的 Redis Key 管理 |
|
||||
| 🚀 | 消息队列 | 基于 Redis 实现消息队列,Stream 提供集群消费,Pub/Sub 提供广播消费 |
|
||||
| 🚀 | Java 监控 | 基于 Spring Boot Admin 实现 Java 应用的监控 |
|
||||
| 🚀 | 链路追踪 | 接入 SkyWalking 组件,实现链路追踪 |
|
||||
| 🚀 | 日志中心 | 接入 SkyWalking 组件,实现日志中心 |
|
||||
| 🚀 | 服务保障 | 基于 Redis 实现分布式锁、幂等、限流功能,满足高并发场景 |
|
||||
| 🚀 | 日志服务 | 轻量级日志中心,查看远程服务器的日志 |
|
||||
| 🚀 | 单元测试 | 基于 JUnit + Mockito 实现单元测试,保证功能的正确性、代码的质量等 |
|
||||
| | 功能 | 描述 |
|
||||
|----|-----------|----------------------------------------------|
|
||||
| 🚀 | 代码生成 | 前后端代码的生成(Java、Vue、SQL、单元测试),支持 CRUD 下载 |
|
||||
| 🚀 | 系统接口 | 基于 Swagger 自动生成相关的 RESTful API 接口文档 |
|
||||
| 🚀 | 数据库文档 | 基于 Screw 自动生成数据库文档,支持导出 Word、HTML、MD 格式 |
|
||||
| | 表单构建 | 拖动表单元素生成相应的 HTML 代码,支持导出 JSON、Vue 文件 |
|
||||
| 🚀 | 配置管理 | 对系统动态配置常用参数,支持 SpringBoot 加载 |
|
||||
| ⭐️ | 定时任务 | 在线(添加、修改、删除)任务调度包含执行结果日志 |
|
||||
| 🚀 | 文件服务 | 支持将文件存储到 S3(MinIO、阿里云、腾讯云、七牛云)、本地、FTP、数据库等 |
|
||||
| 🚀 | WebSocket | 提供 WebSocket 接入示例,支持一对一、一对多发送方式 |
|
||||
| 🚀 | API 日志 | 包括 RESTful API 访问日志、异常日志两部分,方便排查 API 相关的问题 |
|
||||
| | MySQL 监控 | 监视当前系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈 |
|
||||
| | Redis 监控 | 监控 Redis 数据库的使用情况,使用的 Redis Key 管理 |
|
||||
| 🚀 | 消息队列 | 基于 Redis 实现消息队列,Stream 提供集群消费,Pub/Sub 提供广播消费 |
|
||||
| 🚀 | Java 监控 | 基于 Spring Boot Admin 实现 Java 应用的监控 |
|
||||
| 🚀 | 链路追踪 | 接入 SkyWalking 组件,实现链路追踪 |
|
||||
| 🚀 | 日志中心 | 接入 SkyWalking 组件,实现日志中心 |
|
||||
| 🚀 | 服务保障 | 基于 Redis 实现分布式锁、幂等、限流功能,满足高并发场景 |
|
||||
| 🚀 | 日志服务 | 轻量级日志中心,查看远程服务器的日志 |
|
||||
| 🚀 | 单元测试 | 基于 JUnit + Mockito 实现单元测试,保证功能的正确性、代码的质量等 |
|
||||
|
||||

|
||||

|
||||
|
||||
### 数据报表
|
||||
|
||||
@@ -195,43 +197,44 @@
|
||||
|
||||
### 微信公众号
|
||||
|
||||
| | 功能 | 描述 |
|
||||
| --- | --- | --- |
|
||||
| 🚀 | 账号管理 | 配置接入的微信公众号,可支持多个公众号 |
|
||||
| 🚀 | 数据统计 | 统计公众号的用户增减、累计用户、消息概况、接口分析等数据 |
|
||||
| 🚀 | 粉丝管理 | 查看已关注、取关的粉丝列表,可对粉丝进行同步、打标签等操作 |
|
||||
| 🚀 | 消息管理 | 查看粉丝发送的消息列表,可主动回复粉丝消息 |
|
||||
| 🚀 | 自动回复 | 自动回复粉丝发送的消息,支持关注回复、消息回复、关键字回复 |
|
||||
| 🚀 | 标签管理 | 对公众号的标签进行创建、查询、修改、删除等操作 |
|
||||
| 🚀 | 菜单管理 | 自定义公众号的菜单,也可以从公众号同步菜单 |
|
||||
| 🚀 | 素材管理 | 管理公众号的图片、语音、视频等素材,支持在线播放语音、视频 |
|
||||
| 🚀 | 图文草稿箱 | 新增常用的图文素材到草稿箱,可发布到公众号 |
|
||||
| 🚀 | 图文发表记录 | 查看已发布成功的图文素材,支持删除操作 |
|
||||
| | 功能 | 描述 |
|
||||
|----|--------|-------------------------------|
|
||||
| 🚀 | 账号管理 | 配置接入的微信公众号,可支持多个公众号 |
|
||||
| 🚀 | 数据统计 | 统计公众号的用户增减、累计用户、消息概况、接口分析等数据 |
|
||||
| 🚀 | 粉丝管理 | 查看已关注、取关的粉丝列表,可对粉丝进行同步、打标签等操作 |
|
||||
| 🚀 | 消息管理 | 查看粉丝发送的消息列表,可主动回复粉丝消息 |
|
||||
| 🚀 | 模版消息 | 配置和发送模版消息,用于向粉丝推送通知类消息 |
|
||||
| 🚀 | 自动回复 | 自动回复粉丝发送的消息,支持关注回复、消息回复、关键字回复 |
|
||||
| 🚀 | 标签管理 | 对公众号的标签进行创建、查询、修改、删除等操作 |
|
||||
| 🚀 | 菜单管理 | 自定义公众号的菜单,也可以从公众号同步菜单 |
|
||||
| 🚀 | 素材管理 | 管理公众号的图片、语音、视频等素材,支持在线播放语音、视频 |
|
||||
| 🚀 | 图文草稿箱 | 新增常用的图文素材到草稿箱,可发布到公众号 |
|
||||
| 🚀 | 图文发表记录 | 查看已发布成功的图文素材,支持删除操作 |
|
||||
|
||||
### 商城系统
|
||||
|
||||
演示地址:<https://doc.iocoder.cn/mall-preview/>
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||
### ERP 系统
|
||||
|
||||
演示地址:<https://doc.iocoder.cn/erp-preview/>
|
||||
|
||||

|
||||

|
||||
|
||||
### CRM 系统
|
||||
|
||||
演示地址:<https://doc.iocoder.cn/crm-preview/>
|
||||
|
||||

|
||||

|
||||
|
||||
### AI 大模型
|
||||
|
||||
演示地址:<https://doc.iocoder.cn/ai-preview/>
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
PORT=5320
|
||||
ACCESS_TOKEN_SECRET=access_token_secret
|
||||
REFRESH_TOKEN_SECRET=refresh_token_secret
|
||||
@@ -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
|
||||
```
|
||||
@@ -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);
|
||||
});
|
||||
@@ -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,
|
||||
});
|
||||
});
|
||||
@@ -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('');
|
||||
});
|
||||
@@ -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;
|
||||
});
|
||||
@@ -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;
|
||||
});
|
||||
@@ -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);
|
||||
});
|
||||
@@ -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}`);
|
||||
});
|
||||
@@ -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);
|
||||
});
|
||||
@@ -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);
|
||||
});
|
||||
@@ -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);
|
||||
});
|
||||
@@ -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);
|
||||
});
|
||||
@@ -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);
|
||||
});
|
||||
@@ -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);
|
||||
});
|
||||
@@ -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);
|
||||
});
|
||||
@@ -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);
|
||||
});
|
||||
@@ -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,
|
||||
);
|
||||
});
|
||||
@@ -1,3 +0,0 @@
|
||||
import { defineEventHandler } from 'h3';
|
||||
|
||||
export default defineEventHandler(() => 'Test get handler');
|
||||
@@ -1,3 +0,0 @@
|
||||
import { defineEventHandler } from 'h3';
|
||||
|
||||
export default defineEventHandler(() => 'Test post handler');
|
||||
@@ -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")
|
||||
});
|
||||
@@ -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);
|
||||
});
|
||||
@@ -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;
|
||||
@@ -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, '演示环境,禁止修改');
|
||||
}
|
||||
});
|
||||
@@ -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': '*',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -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:"
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
`;
|
||||
});
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"extends": "./.nitro/types/tsconfig.json"
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -1,390 +0,0 @@
|
||||
export interface UserInfo {
|
||||
id: number;
|
||||
password: string;
|
||||
realName: string;
|
||||
roles: string[];
|
||||
username: string;
|
||||
homePath?: 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: 201,
|
||||
name: 'SystemDeptCreate',
|
||||
status: 1,
|
||||
type: 'button',
|
||||
authCode: 'System:Dept:Create',
|
||||
meta: { title: 'common.create' },
|
||||
},
|
||||
{
|
||||
id: 20_402,
|
||||
pid: 201,
|
||||
name: 'SystemDeptEdit',
|
||||
status: 1,
|
||||
type: 'button',
|
||||
authCode: 'System:Dept:Edit',
|
||||
meta: { title: 'common.edit' },
|
||||
},
|
||||
{
|
||||
id: 20_403,
|
||||
pid: 201,
|
||||
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;
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
@@ -43,9 +43,11 @@
|
||||
"@vben/styles": "workspace:*",
|
||||
"@vben/types": "workspace:*",
|
||||
"@vben/utils": "workspace:*",
|
||||
"@videojs-player/vue": "catalog:",
|
||||
"@vueuse/core": "catalog:",
|
||||
"@vueuse/integrations": "catalog:",
|
||||
"ant-design-vue": "catalog:",
|
||||
"benz-amr-recorder": "catalog:",
|
||||
"bpmn-js": "catalog:",
|
||||
"bpmn-js-properties-panel": "catalog:",
|
||||
"bpmn-js-token-simulation": "catalog:",
|
||||
@@ -58,9 +60,11 @@
|
||||
"pinia": "catalog:",
|
||||
"steady-xml": "catalog:",
|
||||
"tinymce": "catalog:",
|
||||
"video.js": "catalog:",
|
||||
"vue": "catalog:",
|
||||
"vue-dompurify-html": "catalog:",
|
||||
"vue-router": "catalog:",
|
||||
"vue3-print-nb": "catalog:",
|
||||
"vue3-signature": "catalog:",
|
||||
"vuedraggable": "catalog:"
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
@@ -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}`);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import { requestClient } from '#/api/request';
|
||||
|
||||
const { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD);
|
||||
const accessStore = useAccessStore();
|
||||
|
||||
export namespace AiChatMessageApi {
|
||||
export interface ChatMessage {
|
||||
id: number; // 编号
|
||||
@@ -18,6 +19,7 @@ export namespace AiChatMessageApi {
|
||||
model: number; // 模型标志
|
||||
modelId: number; // 模型编号
|
||||
content: string; // 聊天内容
|
||||
reasoningContent?: string; // 推理内容(深度思考)
|
||||
tokens: number; // 消耗 Token 数量
|
||||
segmentIds?: number[]; // 段落编号
|
||||
segments?: {
|
||||
@@ -26,13 +28,25 @@ export namespace AiChatMessageApi {
|
||||
documentName: string; // 文档名称
|
||||
id: number; // 段落编号
|
||||
}[];
|
||||
webSearchPages?: WebSearchPage[]; // 联网搜索结果
|
||||
attachmentUrls?: string[]; // 附件 URL 数组
|
||||
createTime: Date; // 创建时间
|
||||
roleAvatar: string; // 角色头像
|
||||
userAvatar: string; // 用户头像
|
||||
}
|
||||
|
||||
/** 联网搜索页面接口 */
|
||||
export interface WebSearchPage {
|
||||
name: string; // 网站名称
|
||||
icon: string; // 网站图标 URL
|
||||
title: string; // 页面标题
|
||||
url: string; // 页面 URL
|
||||
snippet: string; // 简短描述
|
||||
summary: string; // 内容摘要
|
||||
}
|
||||
}
|
||||
|
||||
// 消息列表
|
||||
/** 消息列表 */
|
||||
export function getChatMessageListByConversationId(
|
||||
conversationId: null | number,
|
||||
) {
|
||||
@@ -41,15 +55,17 @@ export function getChatMessageListByConversationId(
|
||||
);
|
||||
}
|
||||
|
||||
// 发送 Stream 消息
|
||||
/** 发送 Stream 消息 */
|
||||
export function sendChatMessageStream(
|
||||
conversationId: number,
|
||||
content: string,
|
||||
ctrl: any,
|
||||
enableContext: boolean,
|
||||
enableWebSearch: boolean,
|
||||
onMessage: any,
|
||||
onError: any,
|
||||
onClose: any,
|
||||
attachmentUrls?: string[],
|
||||
) {
|
||||
const token = accessStore.accessToken;
|
||||
return fetchEventSource(`${apiURL}/ai/chat/message/send-stream`, {
|
||||
@@ -63,6 +79,8 @@ export function sendChatMessageStream(
|
||||
conversationId,
|
||||
content,
|
||||
useContext: enableContext,
|
||||
useSearch: enableWebSearch,
|
||||
attachmentUrls: attachmentUrls || [],
|
||||
}),
|
||||
onmessage: onMessage,
|
||||
onerror: onError,
|
||||
@@ -71,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}`);
|
||||
}
|
||||
|
||||
@@ -3,13 +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; // 样式: 2(Primary)、3(Green)
|
||||
}
|
||||
// AI 绘图
|
||||
/** 绘图 */
|
||||
export interface Image {
|
||||
id: number; // 编号
|
||||
userId: number;
|
||||
@@ -29,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; // 样式: 2(Primary)、3(Green)
|
||||
}
|
||||
|
||||
export interface ImageDrawReqVO {
|
||||
prompt: string; // 提示词
|
||||
modelId: number; // 模型
|
||||
style: string; // 图像生成的风格
|
||||
@@ -38,7 +39,7 @@ export namespace AiImageApi {
|
||||
options: object; // 绘制参数,Map<String, String>
|
||||
}
|
||||
|
||||
export interface ImageMidjourneyImagineReq {
|
||||
export interface ImageMidjourneyImagineReqVO {
|
||||
prompt: string; // 提示词
|
||||
modelId: number; // 模型
|
||||
base64Array?: string[]; // size不能为空
|
||||
@@ -53,58 +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】生成图片
|
||||
export function midjourneyImagine(data: AiImageApi.ImageMidjourneyImagineReq) {
|
||||
/** ================ midjourney 专属 ================ */
|
||||
|
||||
/** 【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}`);
|
||||
}
|
||||
|
||||
@@ -15,36 +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}`);
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ export namespace AiKnowledgeKnowledgeApi {
|
||||
}
|
||||
}
|
||||
|
||||
// 查询知识库分页
|
||||
/** 查询知识库分页 */
|
||||
export function getKnowledgePage(params: PageParam) {
|
||||
return requestClient.get<PageResult<AiKnowledgeKnowledgeApi.Knowledge>>(
|
||||
'/ai/knowledge/page',
|
||||
@@ -21,28 +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',
|
||||
|
||||
@@ -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,50 +25,55 @@ 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(data: any) {
|
||||
return requestClient.put('/ai/knowledge/segment/update-status', data);
|
||||
/** 修改知识库分段状态 */
|
||||
export function updateKnowledgeSegmentStatus(id: number, status: number) {
|
||||
return requestClient.put('/ai/knowledge/segment/update-status', {
|
||||
id,
|
||||
status,
|
||||
});
|
||||
}
|
||||
// 删除知识库分段
|
||||
|
||||
/** 删除知识库分段 */
|
||||
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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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}`);
|
||||
}
|
||||
|
||||
@@ -2,28 +2,48 @@ import type { PageParam, PageResult } from '@vben/request';
|
||||
|
||||
import { requestClient } from '#/api/request';
|
||||
|
||||
export function getWorkflowPage(params: PageParam) {
|
||||
return requestClient.get<PageResult<any>>('/ai/workflow/page', {
|
||||
params,
|
||||
});
|
||||
export namespace AiWorkflowApi {
|
||||
/** 工作流 */
|
||||
export interface Workflow {
|
||||
id?: number; // 编号
|
||||
name: string; // 工作流名称
|
||||
code: string; // 工作流标识
|
||||
graph: string; // 工作流模型 JSON 数据
|
||||
remark?: string; // 备注
|
||||
status: number; // 状态
|
||||
createTime?: Date; // 创建时间
|
||||
}
|
||||
}
|
||||
|
||||
export const getWorkflow = (id: number | string) => {
|
||||
return requestClient.get(`/ai/workflow/get?id=${id}`);
|
||||
};
|
||||
/** 查询工作流管理列表 */
|
||||
export function getWorkflowPage(params: PageParam) {
|
||||
return requestClient.get<PageResult<AiWorkflowApi.Workflow>>(
|
||||
'/ai/workflow/page',
|
||||
{ params },
|
||||
);
|
||||
}
|
||||
|
||||
export const createWorkflow = (data: any) => {
|
||||
/** 查询工作流详情 */
|
||||
export function getWorkflow(id: number) {
|
||||
return requestClient.get<AiWorkflowApi.Workflow>(`/ai/workflow/get?id=${id}`);
|
||||
}
|
||||
|
||||
/** 新增工作流 */
|
||||
export function createWorkflow(data: AiWorkflowApi.Workflow) {
|
||||
return requestClient.post('/ai/workflow/create', data);
|
||||
};
|
||||
}
|
||||
|
||||
export const updateWorkflow = (data: any) => {
|
||||
/** 修改工作流 */
|
||||
export function updateWorkflow(data: AiWorkflowApi.Workflow) {
|
||||
return requestClient.put('/ai/workflow/update', data);
|
||||
};
|
||||
}
|
||||
|
||||
export const deleteWorkflow = (id: number | string) => {
|
||||
/** 删除工作流 */
|
||||
export function deleteWorkflow(id: number) {
|
||||
return requestClient.delete(`/ai/workflow/delete?id=${id}`);
|
||||
};
|
||||
}
|
||||
|
||||
export const testWorkflow = (data: any) => {
|
||||
/** 测试工作流 */
|
||||
export function testWorkflow(data: any) {
|
||||
return requestClient.post('/ai/workflow/test', data);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ export namespace AiWriteApi {
|
||||
}
|
||||
}
|
||||
|
||||
/** 写作 Stream */
|
||||
export function writeStream({
|
||||
data,
|
||||
onClose,
|
||||
|
||||
@@ -1,27 +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;
|
||||
}
|
||||
|
||||
/** 流程模型 */
|
||||
export interface Model {
|
||||
id: number;
|
||||
@@ -42,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;
|
||||
}
|
||||
}
|
||||
|
||||
/** 模型分类信息 */
|
||||
|
||||
@@ -11,43 +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;
|
||||
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;
|
||||
@@ -73,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;
|
||||
@@ -83,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;
|
||||
@@ -101,6 +103,19 @@ export namespace BpmProcessInstanceApi {
|
||||
}[];
|
||||
taskId: string;
|
||||
}
|
||||
|
||||
/** 流程实例的打印数据响应 */
|
||||
export interface ProcessPrintDataRespVO {
|
||||
printTemplateEnable: boolean;
|
||||
printTemplateHtml?: string;
|
||||
processInstance: ProcessInstance;
|
||||
tasks: {
|
||||
description: string;
|
||||
id: number;
|
||||
name: string;
|
||||
signPicUrl?: string;
|
||||
}[];
|
||||
}
|
||||
}
|
||||
|
||||
/** 查询我的流程实例分页 */
|
||||
@@ -177,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 },
|
||||
);
|
||||
@@ -191,17 +206,16 @@ 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>(
|
||||
`/bpm/process-instance/get-bpmn-model-view?id=${id}`,
|
||||
);
|
||||
}
|
||||
|
||||
/** 获取流程实例打印数据 */
|
||||
export async function getProcessInstancePrintData(id: string) {
|
||||
return requestClient.get<BpmProcessInstanceApi.ProcessPrintDataRespVO>(
|
||||
`/bpm/process-instance/get-print-data?processInstanceId=${id}`,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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; // 监听器名字
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
/** 默认商机状态 */
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
/** 查询跟进记录分页 */
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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 });
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
});
|
||||
|
||||
@@ -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 },
|
||||
);
|
||||
|
||||
@@ -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 },
|
||||
);
|
||||
|
||||
@@ -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 },
|
||||
);
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { PageParam, PageResult } from '@vben/request';
|
||||
import { requestClient } from '#/api/request';
|
||||
|
||||
export namespace ErpAccountApi {
|
||||
/** ERP 结算账户信息 */
|
||||
/** 结算账户信息 */
|
||||
export interface Account {
|
||||
id?: number; // 结算账户编号
|
||||
no: string; // 账户编码
|
||||
@@ -13,17 +13,10 @@ export namespace ErpAccountApi {
|
||||
defaultStatus: boolean; // 是否默认
|
||||
name: string; // 账户名称
|
||||
}
|
||||
|
||||
/** 结算账户分页查询参数 */
|
||||
export interface AccountPageParam extends PageParam {
|
||||
name?: string;
|
||||
no?: string;
|
||||
status?: number;
|
||||
}
|
||||
}
|
||||
|
||||
/** 查询结算账户分页 */
|
||||
export function getAccountPage(params: ErpAccountApi.AccountPageParam) {
|
||||
export function getAccountPage(params: PageParam) {
|
||||
return requestClient.get<PageResult<ErpAccountApi.Account>>(
|
||||
'/erp/account/page',
|
||||
{ params },
|
||||
|
||||
@@ -3,19 +3,6 @@ import type { PageParam, PageResult } from '@vben/request';
|
||||
import { requestClient } from '#/api/request';
|
||||
|
||||
export namespace ErpFinancePaymentApi {
|
||||
/** 付款单项 */
|
||||
export interface FinancePaymentItem {
|
||||
id?: number;
|
||||
row_id?: number; // 前端使用的临时ID
|
||||
bizId: number; // 业务ID
|
||||
bizType: number; // 业务类型
|
||||
bizNo: string; // 业务编号
|
||||
totalPrice: number; // 应付金额
|
||||
paidPrice: number; // 已付金额
|
||||
paymentPrice: number; // 本次付款
|
||||
remark?: string; // 备注
|
||||
}
|
||||
|
||||
/** 付款单信息 */
|
||||
export interface FinancePayment {
|
||||
id?: number; // 付款单编号
|
||||
@@ -39,24 +26,22 @@ export namespace ErpFinancePaymentApi {
|
||||
bizNo?: string; // 业务单号
|
||||
}
|
||||
|
||||
/** 付款单分页查询参数 */
|
||||
export interface FinancePaymentPageParams extends PageParam {
|
||||
no?: string;
|
||||
paymentTime?: [string, string];
|
||||
supplierId?: number;
|
||||
creator?: string;
|
||||
financeUserId?: number;
|
||||
accountId?: number;
|
||||
status?: number;
|
||||
remark?: string;
|
||||
bizNo?: string;
|
||||
/** 付款单项 */
|
||||
export interface FinancePaymentItem {
|
||||
id?: number;
|
||||
row_id?: number; // 前端使用的临时 ID
|
||||
bizId: number; // 业务ID
|
||||
bizType: number; // 业务类型
|
||||
bizNo: string; // 业务编号
|
||||
totalPrice: number; // 应付金额
|
||||
paidPrice: number; // 已付金额
|
||||
paymentPrice: number; // 本次付款
|
||||
remark?: string; // 备注
|
||||
}
|
||||
}
|
||||
|
||||
/** 查询付款单分页 */
|
||||
export function getFinancePaymentPage(
|
||||
params: ErpFinancePaymentApi.FinancePaymentPageParams,
|
||||
) {
|
||||
export function getFinancePaymentPage(params: PageParam) {
|
||||
return requestClient.get<PageResult<ErpFinancePaymentApi.FinancePayment>>(
|
||||
'/erp/finance-payment/page',
|
||||
{
|
||||
@@ -103,9 +88,7 @@ export function deleteFinancePayment(ids: number[]) {
|
||||
}
|
||||
|
||||
/** 导出付款单 Excel */
|
||||
export function exportFinancePayment(
|
||||
params: ErpFinancePaymentApi.FinancePaymentPageParams,
|
||||
) {
|
||||
export function exportFinancePayment(params: any) {
|
||||
return requestClient.download('/erp/finance-payment/export-excel', {
|
||||
params,
|
||||
});
|
||||
|
||||
@@ -6,7 +6,7 @@ export namespace ErpFinanceReceiptApi {
|
||||
/** 收款单项 */
|
||||
export interface FinanceReceiptItem {
|
||||
id?: number;
|
||||
row_id?: number; // 前端使用的临时ID
|
||||
row_id?: number; // 前端使用的临时 ID
|
||||
bizId: number; // 业务ID
|
||||
bizType: number; // 业务类型
|
||||
bizNo: string; // 业务编号
|
||||
@@ -38,25 +38,10 @@ export namespace ErpFinanceReceiptApi {
|
||||
items?: FinanceReceiptItem[]; // 收款明细
|
||||
bizNo?: string; // 业务单号
|
||||
}
|
||||
|
||||
/** 收款单分页查询参数 */
|
||||
export interface FinanceReceiptPageParams extends PageParam {
|
||||
no?: string;
|
||||
receiptTime?: [string, string];
|
||||
customerId?: number;
|
||||
creator?: string;
|
||||
financeUserId?: number;
|
||||
accountId?: number;
|
||||
status?: number;
|
||||
remark?: string;
|
||||
bizNo?: string;
|
||||
}
|
||||
}
|
||||
|
||||
/** 查询收款单分页 */
|
||||
export function getFinanceReceiptPage(
|
||||
params: ErpFinanceReceiptApi.FinanceReceiptPageParams,
|
||||
) {
|
||||
export function getFinanceReceiptPage(params: PageParam) {
|
||||
return requestClient.get<PageResult<ErpFinanceReceiptApi.FinanceReceipt>>(
|
||||
'/erp/finance-receipt/page',
|
||||
{
|
||||
@@ -103,9 +88,7 @@ export function deleteFinanceReceipt(ids: number[]) {
|
||||
}
|
||||
|
||||
/** 导出收款单 Excel */
|
||||
export function exportFinanceReceipt(
|
||||
params: ErpFinanceReceiptApi.FinanceReceiptPageParams,
|
||||
) {
|
||||
export function exportFinanceReceipt(params: any) {
|
||||
return requestClient.download('/erp/finance-receipt/export-excel', {
|
||||
params,
|
||||
});
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { requestClient } from '#/api/request';
|
||||
|
||||
export namespace ErpProductCategoryApi {
|
||||
/** ERP 产品分类信息 */
|
||||
/** 产品分类信息 */
|
||||
export interface ProductCategory {
|
||||
id?: number; // 分类编号
|
||||
parentId?: number; // 父分类编号
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { PageParam, PageResult } from '@vben/request';
|
||||
import { requestClient } from '#/api/request';
|
||||
|
||||
export namespace ErpProductApi {
|
||||
/** ERP 产品信息 */
|
||||
/** 产品信息 */
|
||||
export interface Product {
|
||||
id?: number; // 产品编号
|
||||
name: string; // 产品名称
|
||||
|
||||
@@ -3,24 +3,16 @@ import type { PageParam, PageResult } from '@vben/request';
|
||||
import { requestClient } from '#/api/request';
|
||||
|
||||
export namespace ErpProductUnitApi {
|
||||
/** ERP 产品单位信息 */
|
||||
/** 产品单位信息 */
|
||||
export interface ProductUnit {
|
||||
id?: number; // 单位编号
|
||||
name: string; // 单位名字
|
||||
status: number; // 单位状态
|
||||
}
|
||||
|
||||
/** 产品单位分页查询参数 */
|
||||
export interface ProductUnitPageParam extends PageParam {
|
||||
name?: string;
|
||||
status?: number;
|
||||
}
|
||||
}
|
||||
|
||||
/** 查询产品单位分页 */
|
||||
export function getProductUnitPage(
|
||||
params: ErpProductUnitApi.ProductUnitPageParam,
|
||||
) {
|
||||
export function getProductUnitPage(params: PageParam) {
|
||||
return requestClient.get<PageResult<ErpProductUnitApi.ProductUnit>>(
|
||||
'/erp/product-unit/page',
|
||||
{ params },
|
||||
|
||||
@@ -23,6 +23,8 @@ export namespace ErpPurchaseInApi {
|
||||
taxPrice?: number; // 合计税额
|
||||
items?: PurchaseInItem[]; // 采购入库明细
|
||||
}
|
||||
|
||||
/** 采购项信息 */
|
||||
export interface PurchaseInItem {
|
||||
count?: number;
|
||||
id?: number;
|
||||
@@ -42,21 +44,10 @@ export namespace ErpPurchaseInApi {
|
||||
warehouseId?: number;
|
||||
inCount?: number;
|
||||
}
|
||||
|
||||
/** 采购入库分页查询参数 */
|
||||
export interface PurchaseInPageParams extends PageParam {
|
||||
no?: string;
|
||||
supplierId?: number;
|
||||
status?: number;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询采购入库分页
|
||||
*/
|
||||
export function getPurchaseInPage(
|
||||
params: ErpPurchaseInApi.PurchaseInPageParams,
|
||||
) {
|
||||
/** 查询采购入库分页 */
|
||||
export function getPurchaseInPage(params: PageParam) {
|
||||
return requestClient.get<PageResult<ErpPurchaseInApi.PurchaseIn>>(
|
||||
'/erp/purchase-in/page',
|
||||
{
|
||||
@@ -65,32 +56,24 @@ export function getPurchaseInPage(
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询采购入库详情
|
||||
*/
|
||||
/** 查询采购入库详情 */
|
||||
export function getPurchaseIn(id: number) {
|
||||
return requestClient.get<ErpPurchaseInApi.PurchaseIn>(
|
||||
`/erp/purchase-in/get?id=${id}`,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增采购入库
|
||||
*/
|
||||
/** 新增采购入库 */
|
||||
export function createPurchaseIn(data: ErpPurchaseInApi.PurchaseIn) {
|
||||
return requestClient.post('/erp/purchase-in/create', data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改采购入库
|
||||
*/
|
||||
/** 修改采购入库 */
|
||||
export function updatePurchaseIn(data: ErpPurchaseInApi.PurchaseIn) {
|
||||
return requestClient.put('/erp/purchase-in/update', data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新采购入库的状态
|
||||
*/
|
||||
/** 更新采购入库的状态 */
|
||||
export function updatePurchaseInStatus(id: number, status: number) {
|
||||
return requestClient.put('/erp/purchase-in/update-status', null, {
|
||||
params: {
|
||||
@@ -100,9 +83,7 @@ export function updatePurchaseInStatus(id: number, status: number) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除采购入库
|
||||
*/
|
||||
/** 删除采购入库 */
|
||||
export function deletePurchaseIn(ids: number[]) {
|
||||
return requestClient.delete('/erp/purchase-in/delete', {
|
||||
params: {
|
||||
@@ -111,12 +92,8 @@ export function deletePurchaseIn(ids: number[]) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出采购入库 Excel
|
||||
*/
|
||||
export function exportPurchaseIn(
|
||||
params: ErpPurchaseInApi.PurchaseInPageParams,
|
||||
) {
|
||||
/** 导出采购入库 Excel */
|
||||
export function exportPurchaseIn(params: any) {
|
||||
return requestClient.download('/erp/purchase-in/export-excel', {
|
||||
params,
|
||||
});
|
||||
|
||||
@@ -3,27 +3,7 @@ import type { PageParam, PageResult } from '@vben/request';
|
||||
import { requestClient } from '#/api/request';
|
||||
|
||||
export namespace ErpPurchaseOrderApi {
|
||||
/** ERP 采购订单项信息 */
|
||||
export interface PurchaseOrderItem {
|
||||
id?: number; // 订单项编号
|
||||
orderId?: number; // 采购订单编号
|
||||
productId?: number; // 产品编号
|
||||
productName?: string; // 产品名称
|
||||
productBarCode?: string; // 产品条码
|
||||
productUnitId?: number; // 产品单位编号
|
||||
productUnitName?: string; // 产品单位名称
|
||||
productPrice?: number; // 产品单价,单位:元
|
||||
totalProductPrice?: number; // 产品总价,单位:元
|
||||
count?: number; // 数量
|
||||
totalPrice?: number; // 总价,单位:元
|
||||
taxPercent?: number; // 税率,百分比
|
||||
taxPrice?: number; // 税额,单位:元
|
||||
totalTaxPrice?: number; // 含税总价,单位:元
|
||||
remark?: string; // 备注
|
||||
stockCount?: number; // 库存数量(显示字段)
|
||||
}
|
||||
|
||||
/** ERP 采购订单信息 */
|
||||
/** 采购订单信息 */
|
||||
export interface PurchaseOrder {
|
||||
id?: number; // 订单工单编号
|
||||
no?: string; // 采购订单号
|
||||
@@ -51,24 +31,29 @@ export namespace ErpPurchaseOrderApi {
|
||||
items?: PurchaseOrderItem[]; // 订单项列表
|
||||
}
|
||||
|
||||
/** 采购订单分页查询参数 */
|
||||
export interface PurchaseOrderPageParam extends PageParam {
|
||||
no?: string;
|
||||
supplierId?: number;
|
||||
productId?: number;
|
||||
orderTime?: string[];
|
||||
status?: number;
|
||||
remark?: string;
|
||||
creator?: string;
|
||||
inStatus?: number;
|
||||
returnStatus?: number;
|
||||
/** 采购订单项信息 */
|
||||
export interface PurchaseOrderItem {
|
||||
id?: number; // 订单项编号
|
||||
orderId?: number; // 采购订单编号
|
||||
productId?: number; // 产品编号
|
||||
productName?: string; // 产品名称
|
||||
productBarCode?: string; // 产品条码
|
||||
productUnitId?: number; // 产品单位编号
|
||||
productUnitName?: string; // 产品单位名称
|
||||
productPrice?: number; // 产品单价,单位:元
|
||||
totalProductPrice?: number; // 产品总价,单位:元
|
||||
count?: number; // 数量
|
||||
totalPrice?: number; // 总价,单位:元
|
||||
taxPercent?: number; // 税率,百分比
|
||||
taxPrice?: number; // 税额,单位:元
|
||||
totalTaxPrice?: number; // 含税总价,单位:元
|
||||
remark?: string; // 备注
|
||||
stockCount?: number; // 库存数量(显示字段)
|
||||
}
|
||||
}
|
||||
|
||||
/** 查询采购订单分页 */
|
||||
export function getPurchaseOrderPage(
|
||||
params: ErpPurchaseOrderApi.PurchaseOrderPageParam,
|
||||
) {
|
||||
export function getPurchaseOrderPage(params: PageParam) {
|
||||
return requestClient.get<PageResult<ErpPurchaseOrderApi.PurchaseOrder>>(
|
||||
'/erp/purchase-order/page',
|
||||
{ params },
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { PageParam, PageResult } from '@vben/request';
|
||||
import type { PageResult } from '@vben/request';
|
||||
|
||||
import { requestClient } from '#/api/request';
|
||||
|
||||
@@ -19,6 +19,8 @@ export namespace ErpPurchaseReturnApi {
|
||||
otherPrice?: number; // 其他费用
|
||||
items?: PurchaseReturnItem[];
|
||||
}
|
||||
|
||||
/** 采购退货项 */
|
||||
export interface PurchaseReturnItem {
|
||||
count?: number;
|
||||
id?: number;
|
||||
@@ -37,27 +39,10 @@ export namespace ErpPurchaseReturnApi {
|
||||
totalPrice?: number;
|
||||
warehouseId?: number;
|
||||
}
|
||||
|
||||
/** 采购退货分页查询参数 */
|
||||
export interface PurchaseReturnPageParams extends PageParam {
|
||||
no?: string;
|
||||
supplierId?: number;
|
||||
status?: number;
|
||||
}
|
||||
|
||||
/** 采购退货状态更新参数 */
|
||||
export interface PurchaseReturnStatusParams {
|
||||
id: number;
|
||||
status: number;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询采购退货分页
|
||||
*/
|
||||
export function getPurchaseReturnPage(
|
||||
params: ErpPurchaseReturnApi.PurchaseReturnPageParams,
|
||||
) {
|
||||
/** 查询采购退货分页 */
|
||||
export function getPurchaseReturnPage(params: any) {
|
||||
return requestClient.get<PageResult<ErpPurchaseReturnApi.PurchaseReturn>>(
|
||||
'/erp/purchase-return/page',
|
||||
{
|
||||
@@ -66,45 +51,35 @@ export function getPurchaseReturnPage(
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询采购退货详情
|
||||
*/
|
||||
/** 查询采购退货详情 */
|
||||
export function getPurchaseReturn(id: number) {
|
||||
return requestClient.get<ErpPurchaseReturnApi.PurchaseReturn>(
|
||||
`/erp/purchase-return/get?id=${id}`,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增采购退货
|
||||
*/
|
||||
/** 新增采购退货 */
|
||||
export function createPurchaseReturn(
|
||||
data: ErpPurchaseReturnApi.PurchaseReturn,
|
||||
) {
|
||||
return requestClient.post('/erp/purchase-return/create', data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改采购退货
|
||||
*/
|
||||
/** 修改采购退货 */
|
||||
export function updatePurchaseReturn(
|
||||
data: ErpPurchaseReturnApi.PurchaseReturn,
|
||||
) {
|
||||
return requestClient.put('/erp/purchase-return/update', data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新采购退货的状态
|
||||
*/
|
||||
/** 更新采购退货的状态 */
|
||||
export function updatePurchaseReturnStatus(id: number, status: number) {
|
||||
return requestClient.put('/erp/purchase-return/update-status', null, {
|
||||
params: { id, status },
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除采购退货
|
||||
*/
|
||||
/** 删除采购退货 */
|
||||
export function deletePurchaseReturn(ids: number[]) {
|
||||
return requestClient.delete('/erp/purchase-return/delete', {
|
||||
params: {
|
||||
@@ -113,12 +88,8 @@ export function deletePurchaseReturn(ids: number[]) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出采购退货 Excel
|
||||
*/
|
||||
export function exportPurchaseReturn(
|
||||
params: ErpPurchaseReturnApi.PurchaseReturnPageParams,
|
||||
) {
|
||||
/** 导出采购退货 Excel */
|
||||
export function exportPurchaseReturn(params: any) {
|
||||
return requestClient.download('/erp/purchase-return/export-excel', {
|
||||
params,
|
||||
});
|
||||
|
||||