Compare commits

..

84 Commits

Author SHA1 Message Date
xiaojunnuo
3d8f329e2d v1.22.5 2024-07-26 23:15:20 +08:00
xiaojunnuo
351fb70d5d build: prepare to build 2024-07-26 23:14:05 +08:00
xiaojunnuo
b5cbeb9bde chore: 2024-07-26 23:13:50 +08:00
xiaojunnuo
e7e89b8de7 fix: 修复用户管理无法添加用户的bug 2024-07-26 23:07:01 +08:00
xiaojunnuo
225894d15c chore: 2024-07-26 22:48:18 +08:00
xiaojunnuo
64ba485b0f chore: 2024-07-26 22:46:05 +08:00
xiaojunnuo
3a666db36c chore: 2024-07-26 22:16:24 +08:00
xiaojunnuo
ce7e5a2461 chore: 2024-07-26 22:13:49 +08:00
xiaojunnuo
b22f94b079 chore: 2024-07-26 22:11:41 +08:00
xiaojunnuo
3408465df6 chore: 2024-07-26 22:01:42 +08:00
xiaojunnuo
e97dfb456b chore: 2024-07-26 21:42:52 +08:00
xiaojunnuo
439c6c8b6c chore: 2024-07-26 21:42:25 +08:00
xiaojunnuo
afa2b0307a chore: 2024-07-26 21:40:32 +08:00
xiaojunnuo
56867fa777 chore: 2024-07-26 21:37:34 +08:00
xiaojunnuo
9c2e33fa39 chore: 2024-07-26 21:36:25 +08:00
xiaojunnuo
2ca72f838b chore: 2024-07-26 20:56:48 +08:00
xiaojunnuo
37a9e6aae0 v1.22.4 2024-07-26 20:56:06 +08:00
xiaojunnuo
6a8a02dae5 build: prepare to build 2024-07-26 20:55:02 +08:00
xiaojunnuo
eaee5db69e Merge remote-tracking branch 'origin/v2' into v2 2024-07-26 20:54:24 +08:00
xiaojunnuo
25d06904c6 build: prepare to build 2024-07-26 20:54:11 +08:00
xiaojunnuo
fa14f87a80 perf: 支持arm64 2024-07-26 20:53:59 +08:00
xiaojunnuo
4404f99642 Merge remote-tracking branch 'origin/v2' into v2 2024-07-26 09:47:38 +08:00
xiaojunnuo
bafab905b4 chore: 2024-07-25 23:53:00 +08:00
xiaojunnuo
44d5e54550 chore: 2024-07-25 23:42:25 +08:00
xiaojunnuo
a23c13d7d9 chore: 2024-07-25 23:41:19 +08:00
xiaojunnuo
17a7a1432f chore: 2024-07-25 23:38:51 +08:00
xiaojunnuo
26e8932b85 chore: 2024-07-25 23:37:49 +08:00
xiaojunnuo
32beb02d40 chore: 2024-07-25 23:35:34 +08:00
xiaojunnuo
af7177e6bb chore: 2024-07-25 23:29:17 +08:00
xiaojunnuo
69ac0fd0a8 chore: 1.22.3 2024-07-25 23:17:51 +08:00
xiaojunnuo
e0998f35e8 chore: 1.22.3 2024-07-25 23:09:13 +08:00
xiaojunnuo
6d371b38c3 chore: 1.22.3 2024-07-25 23:01:20 +08:00
xiaojunnuo
587f11138a chore: 1.22.3 2024-07-25 22:38:01 +08:00
xiaojunnuo
aa936c279e v1.22.3 2024-07-25 22:34:00 +08:00
xiaojunnuo
5b11d351b2 build: prepare to build 2024-07-25 22:32:48 +08:00
xiaojunnuo
b45b97d3c6 chore: 2024-07-25 22:32:15 +08:00
xiaojunnuo
338eb3bdfe fix: lege 无执行权限问题 2024-07-25 22:25:34 +08:00
Greper
f059e91efc fix: 修复可选链问题导致的响应错误输出报错
修复可选链问题导致的响应错误输出报错
2024-07-25 18:52:17 +08:00
ltxhhz
1cdf1c433f 7.25 patch 2024-07-25 18:13:17 +08:00
xiaojunnuo
a7b8bac4c8 chore: 2024-07-25 11:17:44 +08:00
xiaojunnuo
b7b5df0587 perf: 证书申请支持反向代理,letsencrypt无法访问时的备用方案 2024-07-25 10:38:45 +08:00
xiaojunnuo
4060f6ecbc Merge remote-tracking branch 'origin/v2' into v2
# Conflicts:
#	.github/workflows/build-image.yml
#	build.trigger
2024-07-24 10:55:21 +08:00
xiaojunnuo
7cb5f21444 chore: 2024-07-24 02:29:53 +08:00
xiaojunnuo
e5da46cfc3 v1.22.2 2024-07-24 02:25:12 +08:00
xiaojunnuo
eabb3e38b5 chore: 2024-07-24 02:24:37 +08:00
xiaojunnuo
46140c8efa build: prepare to build 2024-07-24 02:24:04 +08:00
xiaojunnuo
95d071ba56 chore: 2024-07-24 02:23:09 +08:00
xiaojunnuo
3c9c3ca3b0 build: prepare to build 2024-07-24 02:19:05 +08:00
xiaojunnuo
e7c4ade57d build: prepare to build 2024-07-24 02:18:13 +08:00
xiaojunnuo
ca524657b6 build: prepare to build 2024-07-24 02:17:12 +08:00
xiaojunnuo
bc02559bc7 chore: 2024-07-24 02:17:06 +08:00
xiaojunnuo
741172fd98 chore: 2024-07-24 02:16:12 +08:00
xiaojunnuo
83d0209775 chore: 2024-07-24 02:11:38 +08:00
xiaojunnuo
6693d1acfb chore: 2024-07-24 00:42:50 +08:00
xiaojunnuo
a2c43b50a6 fix: 修复创建流水线时,无法根据dns类型默认正确的dns授权的bug
Closes https://github.com/certd/certd/issues/97
2024-07-24 00:42:33 +08:00
xiaojunnuo
f7fc06e657 chore: 2024-07-23 23:39:13 +08:00
xiaojunnuo
b9fe3b9c87 chore: github action build image 2024-07-23 23:23:45 +08:00
xiaojunnuo
06be993afc chore: github action build image 2024-07-23 23:16:55 +08:00
xiaojunnuo
b6ef39fb30 chore: github action build image 2024-07-23 23:12:50 +08:00
xiaojunnuo
0b131c00ed chore: github action build image 2024-07-23 23:06:11 +08:00
xiaojunnuo
b6b8661c36 chore: github action build image 2024-07-23 23:03:15 +08:00
xiaojunnuo
7bf19f8f6f chore: github action build image 2024-07-23 23:00:56 +08:00
xiaojunnuo
c9d9c6513b chore: github action build image 2024-07-23 22:59:23 +08:00
xiaojunnuo
4e7b7ae974 chore: github action build image 2024-07-23 22:57:55 +08:00
xiaojunnuo
dfcabc02a4 chore: github action build image 2024-07-23 22:56:16 +08:00
xiaojunnuo
6f2c5674c9 chore: github action build image 2024-07-23 22:54:23 +08:00
xiaojunnuo
2877b9b505 chore: github action build image 2024-07-23 22:52:56 +08:00
xiaojunnuo
e40bb9e14d chore: github action build image 2024-07-23 22:50:15 +08:00
xiaojunnuo
d456ff9830 chore: github action build image 2024-07-23 22:48:30 +08:00
xiaojunnuo
ffddb3b4ac chore: github action build image 2024-07-23 22:40:05 +08:00
xiaojunnuo
a6113f237b chore: 2024-07-23 22:38:38 +08:00
xiaojunnuo
093520b686 chore: 2024-07-23 22:37:32 +08:00
xiaojunnuo
3a8d44b8e9 chore: github action build 2024-07-23 13:38:52 +08:00
xiaojunnuo
72bff652f7 chore: github action build 2024-07-23 13:30:36 +08:00
xiaojunnuo
9559bdf817 chore: github action build 2024-07-23 13:27:17 +08:00
xiaojunnuo
5a88b8c24e chore: github action build 2024-07-23 12:44:42 +08:00
xiaojunnuo
a9ebac82c7 chore: github action build 2024-07-23 12:43:10 +08:00
xiaojunnuo
cfd8836083 chore: github action build 2024-07-23 12:42:48 +08:00
xiaojunnuo
e01e59b188 chore: github action build 2024-07-23 12:41:36 +08:00
xiaojunnuo
d2fd729961 chore: github action build 2024-07-23 12:40:36 +08:00
xiaojunnuo
5d4ff2e3b7 chore: github action build 2024-07-23 12:39:03 +08:00
xiaojunnuo
6e5133f6b8 chore: github action build 2024-07-23 12:37:21 +08:00
xiaojunnuo
a96d5839b2 chore: github action build 2024-07-23 12:35:24 +08:00
xiaojunnuo
a827bc306a chore: 2024-07-21 03:21:51 +08:00
506 changed files with 459 additions and 29142 deletions

69
.github/workflows/build-image.yml vendored Normal file
View File

@@ -0,0 +1,69 @@
name: build-image
on:
push:
branches: ['v2']
paths:
- "build.trigger"
# schedule:
# - # 国际时间 19:17 执行北京时间3:17 ↙↙↙ 改成你想要每天自动执行的时间
# - cron: '17 19 * * *'
permissions:
contents: read
jobs:
build-certd-image:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: get_certd_version
id: get_certd_version
uses: actions/github-script@v6
with:
result-encoding: string
script: |
const fs = require('fs');
const path = require('path');
const pnpmWorkspace = "./pnpm-workspace.yaml";
fs.unlinkSync(pnpmWorkspace)
const jsonFilePath = "./packages/ui/certd-server/package.json";
const jsonContent = fs.readFileSync(jsonFilePath, 'utf-8');
const pkg = JSON.parse(jsonContent)
console.log("certd_version:",pkg.version);
return pkg.version
# - name: Use Node.js
# uses: actions/setup-node@v4
# with:
# node-version: 18
# cache: 'npm'
# working-directory: ./packages/ui/certd-client
- run: |
npm install -g pnpm
pnpm install
npm run build
working-directory: ./packages/ui/certd-client
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to aliyun container Registry
uses: docker/login-action@v3
with:
registry: registry.cn-shenzhen.aliyuncs.com
username: ${{ secrets.aliyun_cs_username }}
password: ${{ secrets.aliyun_cs_password }}
- name: Build and push
uses: docker/build-push-action@v6.5.0
with:
platforms: linux/amd64,linux/arm64,linux/arm/v7
push: true
context: ./packages/ui/
tags: |
registry.cn-shenzhen.aliyuncs.com/handsfree/certd:latest
registry.cn-shenzhen.aliyuncs.com/handsfree/certd:${{steps.get_certd_version.outputs.result}}

View File

@@ -2,8 +2,6 @@ name: sync-to-gitee
on:
push:
branches: ['v2']
pull_request:
branches: ['v2']
# schedule:
# - # 国际时间 19:17 执行北京时间3:17 ↙↙↙ 改成你想要每天自动执行的时间
# - cron: '17 19 * * *'

View File

@@ -3,6 +3,31 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.22.5](https://github.com/certd/certd/compare/v1.22.4...v1.22.5) (2024-07-26)
### Bug Fixes
* 修复用户管理无法添加用户的bug ([e7e89b8](https://github.com/certd/certd/commit/e7e89b8de7386e84c0d6b8e217e2034909657d68))
## [1.22.4](https://github.com/certd/certd/compare/v1.22.3...v1.22.4) (2024-07-26)
### Performance Improvements
* 证书申请支持反向代理letsencrypt无法访问时的备用方案 ([b7b5df0](https://github.com/certd/certd/commit/b7b5df0587e0f7ea288c1b2af6f87211f207395f))
* 支持arm64 ([fa14f87](https://github.com/certd/certd/commit/fa14f87a8093ef3addc5e5f3315ce1bfc9982782))
## [1.22.3](https://github.com/certd/certd/compare/v1.22.2...v1.22.3) (2024-07-25)
### Bug Fixes
* lege 无执行权限问题 ([338eb3b](https://github.com/certd/certd/commit/338eb3bdfeb461e9b3bc7eee97b97a59f5642ffe))
## [1.22.2](https://github.com/certd/certd/compare/v1.22.1...v1.22.2) (2024-07-23)
### Bug Fixes
* 修复创建流水线时无法根据dns类型默认正确的dns授权的bug ([a2c43b5](https://github.com/certd/certd/commit/a2c43b50a6069ed48958fd142844a8568c2af452))
## [1.22.1](https://github.com/certd/certd/compare/v1.22.0...v1.22.1) (2024-07-20)
### Performance Improvements

101
README.md
View File

@@ -8,16 +8,14 @@ CertD 是一个免费全自动申请和自动部署更新SSL证书的工具。
## 一、特性
本项目不仅支持证书申请过程自动化,还可以自动化部署更新证书,让你的证书永不过期。
* 全自动申请证书支持阿里云、腾讯云、华为云、Cloudflare注册的域名
* 全自动部署更新证书(目前支持服务器上传部署、部署到阿里云、腾讯云等)
* 支持通配符域名
* 支持多个域名打到一个证书上
* 全自动申请证书支持阿里云、腾讯云、华为云、Cloudflare等各种途径注册的域名)
* 全自动部署更新证书(目前支持部署到主机、部署到阿里云、腾讯云等)
* 支持通配符域名/泛域名,支持多个域名打到一个证书上
* 邮件通知
* 证书自动更新
* 私有化部署,保障安全
* 免费、免费、免费([阿里云单个通配符域名证书最便宜也要1800/年](https://yundun.console.aliyun.com/?p=cas#/certExtend/buy/cn-hangzhou)
## 二、在线体验
官方Demo地址自助注册后体验
@@ -40,7 +38,9 @@ https://certd.handsfree.work/
-------> [点我查看详细使用步骤演示](./step.md) <--------
↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
## 四、本地docker部署
## 四、私有化部署
由于证书、授权信息等属于高度敏感数据,请务必私有化部署,保障数据安全
### 1. 安装docker、docker-compose
@@ -49,61 +49,71 @@ https://certd.handsfree.work/
* 【腾讯云】云服务器2核2G新老用户同享99元/年,续费同价!【 [立即购买](https://cloud.tencent.com/act/cps/redirect?redirect=6094&cps_key=b3ef73330335d7a6efa4a4bbeeb6b2c9&from=console)】
1.2 安装docker
https://docs.docker.com/engine/install/
选择对应的操作系统,按照官方文档执行命令即可
1.2 安装docker
https://docs.docker.com/engine/install/
选择对应的操作系统,按照官方文档执行命令即可
### 2. 下载docker-compose.yaml文件
### 2. 运行certd
[docker-compose.yaml下载](https://gitee.com/certd/certd/raw/v2/docker/run/docker-compose.yaml)
[docker-compose.yaml 下载](https://gitee.com/certd/certd/raw/v2/docker/run/docker-compose.yaml)
当前版本号: ![](https://img.shields.io/npm/v/%40certd%2Fpipeline)
```bash
# 随便创建一个目录
mkdir certd
# 进入目录
cd certd
# wget下载docker-compose.yaml文件
wget https://raw.githubusercontent.com/certd/certd/v2/docker/run/docker-compose.yaml
# 或者使用gitee地址
# 下载docker-compose.yaml文件或者手动下载放到certd目录下
wget https://gitee.com/certd/certd/raw/v2/docker/run/docker-compose.yaml
# 可以根据需要修改里面的配置
# 1.修改镜像版本号【可选】
# 2.配置数据保存路径【可选】
# 3.修改端口号【可选】
vi docker-compose.yaml
```
### 3. 运行
当前版本号: ![](https://img.shields.io/npm/v/%40certd%2Fpipeline)
```bash
# 设置镜像版本号环境变量如果docker-compose.yaml中已经修改请忽略这条命令
export CERTD_VERSION=latest # <---建议设置成固定版本号
vi docker-compose.yaml # 【可选】
# 启动certd
docker compose up -d
```
如果提示 没有compose命令,请安装docker-compose
https://docs.docker.com/compose/install/linux/
> 如果提示 没有compose命令,请安装docker-compose
> https://docs.docker.com/compose/install/linux/
#### 镜像说明:
* certd镜像地址:
* `registry.cn-shenzhen.aliyuncs.com/handsfree/certd:latest`
* 镜像构建通过`Actions`自动执行,过程公开透明,请放心使用
* [点我查看镜像构建日志](https://github.com/certd/certd/actions/workflows/build-image.yml)
![](./doc/images/action-build.jpg)
### 4. 访问
### 3. 访问
http://your_server_ip:7001
默认账号密码admin/123456
记得修改密码
### 5. 升级
## 五、 升级
如果使用固定版本号
1. 修改`docker-compose.yaml`中的镜像版本号
2. 运行 `docker compose up -d` 即可
* 修改版本号,重新运行 `docker compose up -d` 即可
* 数据存在`/data/certd`目录下,不用担心数据丢失
如果使用`latest`版本
1. 重新拉取镜像 `docker pull registry.cn-shenzhen.aliyuncs.com/handsfree/certd:latest`
2. 重新启动容器 `docker compose restart`
> 数据默认存在`/data/certd`目录下,不用担心数据丢失
## 五、一些说明
更新日志: [CHANGELOG](./CHANGELOG.md)
## 六、一些说明
* 本项目ssl证书提供商为letencrypt
* 申请过程遵循acme协议
* 需要验证域名所有权一般有两种方式目前本项目仅支持dns-01
@@ -115,14 +125,15 @@ http://your_server_ip:7001
* 免费证书过期时间90天以后可能还会缩短所以自动化部署必不可少
* 设置每天自动运行当证书过期前20天会自动重新申请证书并部署
## 六、不同平台的设置说明
## 七、不同平台的设置说明
* [Cloudflare](./doc/cf/cf.md)
* [腾讯云](./doc/tencent/tencent.md)
* [windows主机](./doc/host/host.md)
## 、问题处理
## 、问题处理
### 7.1 忘记管理员密码
解决方法如下:
1. 修改docker-compose.yaml文件将环境变量`certd_system_resetAdminPassword`改为`true`
@@ -143,9 +154,9 @@ docker logs -f --tail 500 certd
```shell
docker compose up -d
```
5. 使用admin/123456登录系统请及时修改管理员密码
5. 使用`admin/123456`登录系统,请及时修改管理员密码
## 、联系作者
## 、联系作者
如有疑问欢迎加入群聊请备注certd
* QQ群141236433
* 微信群:
@@ -157,7 +168,7 @@ docker compose up -d
<img height="230" src="./doc/images/me.png">
</p>
## 、捐赠
## 、捐赠
媳妇儿说:“一天到晚搞开源,也不管管老婆孩子!😡😡😡”
拜托各位捐赠支持一下,让媳妇儿开心开心,我也能有更多时间进行开源项目,感谢🙏🙏🙏
<p align="center">
@@ -165,16 +176,20 @@ docker compose up -d
</p>
## 十、贡献代码
## 十、贡献代码
[贡献插件教程](./plugin.md)
## 十、我的其他项目求Star
## 十、我的其他项目求Star
* [袖手GPT](https://ai.handsfree.work/) ChatGPT国内可用无需FQ每日免费额度
* [fast-crud](https://gitee.com/fast-crud/fast-crud/) 基于vue3的crud快速开发框架
* [dev-sidecar](https://github.com/docmirror/dev-sidecar/) 直连访问github工具无需FQ解决github无法访问的问题
## 十二、版本更新日志
https://github.com/certd/certd/blob/v2/CHANGELOG.md
## 十三、更新日志
更新日志:[CHANGELOG](./CHANGELOG.md)

1
build.trigger Normal file
View File

@@ -0,0 +1 @@
6

BIN
doc/images/action-build.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

View File

@@ -1,25 +0,0 @@
FROM registry.cn-shenzhen.aliyuncs.com/handsfree/node:18-alpine
EXPOSE 7001
WORKDIR /app/
ENV node_sqlite3_binary_host_mirror https://registry.npmmirror.com/-/binary/sqlite3
RUN npm install -g pnpm@8.15.7 --registry=https://registry.npmmirror.com
RUN pnpm config set registry https://registry.npmmirror.com/
#RUN npm install cross-env -g --registry=https://registry.npmmirror.com
#RUN npm install pm2 -g --registry=https://registry.npmmirror.com
#RUN pm2 install pm2-logrotate
ADD ./workspace/certd-server/ /app/
RUN sed -i "s/workspace://g" "/app/package.json"
#RUN yarn install --registry=https://registry.npmmirror.com
#RUN yarn install --production
RUN pnpm install
RUN node ./before-build.js
RUN npm run build
ENV NODE_ENV production
ENV MIDWAY_SERVER_ENV production
#CMD ["pm2-runtime", "start", "./bootstrap.js","--name", "certd","-i","1"]
CMD ["npm", "run","start"]

View File

@@ -1,38 +0,0 @@
#!/bin/bash
set -e
echo "请先输入一个版本号:"
read version
echo "您输入的版本号是: $version"
echo "登录aliyun镜像仓库"
sudo docker login --username=252959493@qq.com registry.cn-shenzhen.aliyuncs.com
build=$(pwd)
cd ../../
root=$(pwd)
echo "安装依赖"
#pnpm install --registry=https://registry.npmmirror.com
pnpm install
echo "packages build"
lerna run build
echo "packages build success"
echo "server build"
cd $root/packages/ui/certd-server
pnpm run build
echo "server build success"
echo "rm node_modules"
rm ./node_modules -rf
echo "copy to workspace"
mkdir -p $build/workspace/certd-server
\cp ./* $build/workspace/certd-server -rf
\cp ../certd-client/dist/* $build/workspace/certd-server/public/ -rf
#export TAG=$version
#sudo -E docker compose build
#sudo -E docker compose push

View File

@@ -1,15 +0,0 @@
version: '3.3' # 指定docker-compose 版本
services: # 要拉起的服务们
certd:
build:
context: ./
dockerfile: Dockerfile
image: registry.cn-shenzhen.aliyuncs.com/handsfree/certd:${TAG}
container_name: certd # 容器名
restart: unless-stopped # 重启
ports: # 端口映射
- "7001:7001"
environment:
- TZ=Asia/Shanghai
- node_sqlite3_binary_host_mirror=https://registry.npmmirror.com/-/binary/sqlite3

View File

@@ -1,8 +1,8 @@
version: '3.3'
services:
certd:
# 镜像 # ↓↓↓↓↓ --- 1、 修改镜像版本号,或者干脆写成latest不推荐 如果设置了环境变量 export CERTD_VERSION=xxx这里可以不修改
image: registry.cn-shenzhen.aliyuncs.com/handsfree/certd:${CERTD_VERSION}
# 镜像 # ↓↓↓↓↓ --- 1、 镜像版本号,建议改成固定版本号【可选】
image: registry.cn-shenzhen.aliyuncs.com/handsfree/certd:latest
container_name: certd # 容器名
restart: unless-stopped # 自动重启
volumes:

View File

@@ -1,13 +0,0 @@
#!/bin/bash
set -e
# 判断$CERTD_VERSION 是否存在
if [ -n "$CERTD_VERSION" ]; then
echo "CERTD_VERSION is set = $CERTD_VERSION"
else
echo "CERTD_VERSION is not set"
echo "请先输入一个版本号(如 1.0.6)"
read CERTD_VERSION
fi
echo "您输入的版本号是: $CERTD_VERSION"
sudo -E docker compose up -d

View File

@@ -9,5 +9,5 @@
}
},
"npmClient": "pnpm",
"version": "1.22.1"
"version": "1.22.5"
}

View File

@@ -12,10 +12,10 @@
"scripts": {
"start": "lerna bootstrap --hoist",
"i-all": "lerna link && lerna exec npm install ",
"publish": "npm run prepublishOnly1 && lerna publish --conventional-commits && npm run afterpublishOnly && npm run deploy1",
"afterpublishOnly": "",
"publish": "npm run prepublishOnly1 && lerna publish --conventional-commits --create-release github && npm run afterpublishOnly",
"afterpublishOnly": "time /t >build.trigger && git add ./build.md && git commit -m \"build: trigger build image\" && TIMEOUT /T 10 && git push",
"prepublishOnly1": "npm run check && npm run before-build && lerna run build ",
"before-build": "cd ./packages/core/acme-client && time /t >build.md && git add ./build.md && git commit -m \"build: prepare to build\"",
"before-build": "cd ./packages/core/pipeline && time /t >build.md && git add ./build.md && git commit -m \"build: prepare to build\"",
"deploy1": "node --experimental-json-modules deploy.js ",
"check": "node --experimental-json-modules publish-check.js",
"init": "lerna run build"

View File

@@ -3,6 +3,20 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.22.4](https://github.com/publishlab/node-acme-client/compare/v1.22.3...v1.22.4) (2024-07-26)
### Performance Improvements
* 证书申请支持反向代理letsencrypt无法访问时的备用方案 ([b7b5df0](https://github.com/publishlab/node-acme-client/commit/b7b5df0587e0f7ea288c1b2af6f87211f207395f))
## [1.22.3](https://github.com/publishlab/node-acme-client/compare/v1.22.2...v1.22.3) (2024-07-25)
**Note:** Version bump only for package @certd/acme-client
## [1.22.2](https://github.com/publishlab/node-acme-client/compare/v1.22.1...v1.22.2) (2024-07-23)
**Note:** Version bump only for package @certd/acme-client
## [1.22.1](https://github.com/publishlab/node-acme-client/compare/v1.22.0...v1.22.1) (2024-07-20)
**Note:** Version bump only for package @certd/acme-client

View File

@@ -1 +1 @@
03:10
20:55

View File

@@ -3,7 +3,7 @@
"description": "Simple and unopinionated ACME client",
"private": false,
"author": "nmorsman",
"version": "1.22.1",
"version": "1.22.4",
"main": "src/index.js",
"types": "types/index.d.ts",
"license": "MIT",
@@ -59,5 +59,5 @@
"bugs": {
"url": "https://github.com/publishlab/node-acme-client/issues"
},
"gitHead": "47fe3d5826661f678d081ab53e67c847a3239d88"
"gitHead": "e5da46cfc31b2e30a4903bcb2251b1851265ef41"
}

View File

@@ -100,7 +100,7 @@ class AcmeClient {
max: this.opts.backoffMax,
};
this.http = new HttpClient(this.opts.directoryUrl, this.opts.accountKey, this.opts.externalAccountBinding);
this.http = new HttpClient(this.opts.directoryUrl, this.opts.accountKey, this.opts.externalAccountBinding, this.opts.urlMapping);
this.api = new AcmeApi(this.http, this.opts.accountUrl);
}

View File

@@ -12,10 +12,11 @@ const httpsProxy = process.env.HTTPS_PROXY || process.env.https_proxy;
let httpsAgent = null;
if (httpsProxy) {
httpsAgent = new HttpsProxyAgent(httpsProxy);
log(`use https_proxy:${httpsProxy}`);
}
const axios = axios1.create({
proxy: false,
httpsAgent
httpsAgent,
});
/**
@@ -30,7 +31,7 @@ const axios = axios1.create({
*/
class HttpClient {
constructor(directoryUrl, accountKey, externalAccountBinding = {}) {
constructor(directoryUrl, accountKey, externalAccountBinding = {}, urlMapping = {}) {
this.directoryUrl = directoryUrl;
this.accountKey = accountKey;
this.externalAccountBinding = externalAccountBinding;
@@ -41,6 +42,7 @@ class HttpClient {
this.directoryCache = null;
this.directoryMaxAge = 86400;
this.directoryTimestamp = 0;
this.urlMapping = urlMapping;
}
/**
@@ -53,6 +55,16 @@ class HttpClient {
*/
async request(url, method, opts = {}) {
if (this.urlMapping && this.urlMapping.enabled === true && this.urlMapping.mappings) {
// eslint-disable-next-line no-restricted-syntax
for (const key in this.urlMapping.mappings) {
if (url.includes(key)) {
const newUrl = url.replace(key, this.urlMapping.mappings[key]);
log(`use reverse proxy: ${newUrl}`);
url = newUrl;
}
}
}
opts.url = url;
opts.method = method;
opts.validateStatus = null;

View File

@@ -1,4 +1,5 @@
{
"compileOnSave": false,
"compilerOptions": {
"module": "commonjs",
"lib": ["es6"],

View File

@@ -27,6 +27,11 @@ export interface Authorization extends rfc8555.Authorization {
url: string;
}
export type UrlMapping={
enabled: boolean
mappings: Record<string, string>
}
/**
* Client
*/
@@ -39,6 +44,7 @@ export interface ClientOptions {
backoffAttempts?: number;
backoffMin?: number;
backoffMax?: number;
urlMapping?: UrlMapping;
}
export interface ClientExternalAccountBindingOptions {

View File

@@ -3,6 +3,18 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.22.5](https://github.com/certd/certd/compare/v1.22.4...v1.22.5) (2024-07-26)
**Note:** Version bump only for package @certd/pipeline
## [1.22.3](https://github.com/certd/certd/compare/v1.22.2...v1.22.3) (2024-07-25)
**Note:** Version bump only for package @certd/pipeline
## [1.22.2](https://github.com/certd/certd/compare/v1.22.1...v1.22.2) (2024-07-23)
**Note:** Version bump only for package @certd/pipeline
## [1.22.1](https://github.com/certd/certd/compare/v1.22.0...v1.22.1) (2024-07-20)
### Performance Improvements

View File

@@ -0,0 +1 @@
23:14

View File

@@ -1,7 +1,7 @@
{
"name": "@certd/pipeline",
"private": false,
"version": "1.22.1",
"version": "1.22.5",
"type": "module",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
@@ -55,5 +55,5 @@
"vite": "^4.3.8",
"vue-tsc": "^1.6.5"
},
"gitHead": "47fe3d5826661f678d081ab53e67c847a3239d88"
"gitHead": "e5da46cfc31b2e30a4903bcb2251b1851265ef41"
}

View File

@@ -283,7 +283,7 @@ export class Executor {
}
if (notification.type === "email") {
try {
this.options.emailService?.send({
await this.options.emailService?.send({
userId: this.pipeline.userId,
subject,
content,

View File

@@ -50,7 +50,7 @@ export function createAxiosService({ logger }: { logger: Logger }) {
// case 505: error.message = 'HTTP版本不受支持'; break
// default: break
// }
logger.error(`请求出错url:${error?.response?.config.url},method:${error.response.config.method},status:${error?.response?.status}`);
logger.error(`请求出错url:${error?.response?.config.url},method:${error?.response?.config?.method},status:${error?.response?.status}`);
logger.info("返回数据:", JSON.stringify(error?.response?.data));
delete error.config;
delete error.response;

View File

@@ -3,6 +3,18 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.22.5](https://github.com/certd/certd/compare/v1.22.4...v1.22.5) (2024-07-26)
**Note:** Version bump only for package @certd/lib-k8s
## [1.22.3](https://github.com/certd/certd/compare/v1.22.2...v1.22.3) (2024-07-25)
**Note:** Version bump only for package @certd/lib-k8s
## [1.22.2](https://github.com/certd/certd/compare/v1.22.1...v1.22.2) (2024-07-23)
**Note:** Version bump only for package @certd/lib-k8s
## [1.22.1](https://github.com/certd/certd/compare/v1.22.0...v1.22.1) (2024-07-20)
**Note:** Version bump only for package @certd/lib-k8s

View File

@@ -1,7 +1,7 @@
{
"name": "@certd/lib-k8s",
"private": false,
"version": "1.22.1",
"version": "1.22.5",
"type": "module",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
@@ -17,7 +17,7 @@
"shelljs": "^0.8.5"
},
"devDependencies": {
"@certd/pipeline": "^1.22.1",
"@certd/pipeline": "^1.22.5",
"@rollup/plugin-commonjs": "^23.0.4",
"@rollup/plugin-json": "^6.0.0",
"@rollup/plugin-node-resolve": "^15.0.1",
@@ -38,5 +38,5 @@
"tslib": "^2.5.2",
"typescript": "^4.8.4"
},
"gitHead": "47fe3d5826661f678d081ab53e67c847a3239d88"
"gitHead": "e5da46cfc31b2e30a4903bcb2251b1851265ef41"
}

View File

@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.22.3](https://github.com/certd/certd/compare/v1.22.2...v1.22.3) (2024-07-25)
**Note:** Version bump only for package @certd/midway-flyway-js
## [1.22.2](https://github.com/certd/certd/compare/v1.22.1...v1.22.2) (2024-07-23)
**Note:** Version bump only for package @certd/midway-flyway-js
## [1.22.1](https://github.com/certd/certd/compare/v1.22.0...v1.22.1) (2024-07-20)
**Note:** Version bump only for package @certd/midway-flyway-js

View File

@@ -1,6 +1,6 @@
{
"name": "@certd/midway-flyway-js",
"version": "1.22.1",
"version": "1.22.3",
"description": "midway with flyway, sql upgrade way ",
"private": false,
"type": "module",
@@ -53,5 +53,5 @@
"typeorm": "^0.3.11",
"typescript": "~5.1.0"
},
"gitHead": "47fe3d5826661f678d081ab53e67c847a3239d88"
"gitHead": "e5da46cfc31b2e30a4903bcb2251b1851265ef41"
}

View File

@@ -227,8 +227,10 @@ export class Flyway {
if (history.hash !== hash && this.allowHashNotMatch === false) {
throw new Error(file + `hash conflict ,old: ${history.hash} != new: ${hash}`);
}
this.logger.info('[ midfly ] script<' + file + '> already executed');
return true;
}
this.logger.info('[ midfly ] script<' + file + '> not yet execute');
return false;
}

View File

@@ -3,6 +3,24 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.22.5](https://github.com/certd/certd/compare/v1.22.4...v1.22.5) (2024-07-26)
**Note:** Version bump only for package @certd/plugin-cert
## [1.22.4](https://github.com/certd/certd/compare/v1.22.3...v1.22.4) (2024-07-26)
### Performance Improvements
* 证书申请支持反向代理letsencrypt无法访问时的备用方案 ([b7b5df0](https://github.com/certd/certd/commit/b7b5df0587e0f7ea288c1b2af6f87211f207395f))
## [1.22.3](https://github.com/certd/certd/compare/v1.22.2...v1.22.3) (2024-07-25)
**Note:** Version bump only for package @certd/plugin-cert
## [1.22.2](https://github.com/certd/certd/compare/v1.22.1...v1.22.2) (2024-07-23)
**Note:** Version bump only for package @certd/plugin-cert
## [1.22.1](https://github.com/certd/certd/compare/v1.22.0...v1.22.1) (2024-07-20)
### Performance Improvements

View File

@@ -1,7 +1,7 @@
{
"name": "@certd/plugin-cert",
"private": false,
"version": "1.22.1",
"version": "1.22.5",
"type": "module",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
@@ -13,8 +13,8 @@
"preview": "vite preview"
},
"dependencies": {
"@certd/acme-client": "^1.22.1",
"@certd/pipeline": "^1.22.1",
"@certd/acme-client": "^1.22.4",
"@certd/pipeline": "^1.22.5",
"jszip": "^3.10.1",
"node-forge": "^0.10.0",
"psl": "^1.9.0"
@@ -53,5 +53,5 @@
"vite": "^3.1.0",
"vue-tsc": "^0.38.9"
},
"gitHead": "47fe3d5826661f678d081ab53e67c847a3239d88"
"gitHead": "e5da46cfc31b2e30a4903bcb2251b1851265ef41"
}

View File

@@ -6,7 +6,7 @@ import { Logger } from "log4js";
import { IContext } from "@certd/pipeline";
import { IDnsProvider } from "../../dns-provider/index.js";
import psl from "psl";
import { ClientExternalAccountBindingOptions } from "@certd/acme-client";
import { ClientExternalAccountBindingOptions, UrlMapping } from "@certd/acme-client";
export type CertInfo = {
crt: string;
@@ -14,19 +14,24 @@ export type CertInfo = {
csr: string;
};
export type SSLProvider = "letsencrypt" | "buypass" | "zerossl";
type AcmeServiceOptions = {
userContext: IContext;
logger: Logger;
sslProvider: SSLProvider;
eab?: ClientExternalAccountBindingOptions;
skipLocalVerify?: boolean;
useMappingProxy?: boolean;
};
export class AcmeService {
options: AcmeServiceOptions;
userContext: IContext;
logger: Logger;
sslProvider: SSLProvider;
skipLocalVerify = true;
eab?: ClientExternalAccountBindingOptions;
constructor(options: {
userContext: IContext;
logger: Logger;
sslProvider: SSLProvider;
eab?: ClientExternalAccountBindingOptions;
skipLocalVerify?: boolean;
}) {
constructor(options: AcmeServiceOptions) {
this.options = options;
this.userContext = options.userContext;
this.logger = options.logger;
this.sslProvider = options.sslProvider || "letsencrypt";
@@ -61,6 +66,13 @@ export class AcmeService {
} else {
directoryUrl = acme.directory[this.sslProvider].production;
}
const urlMapping: UrlMapping = { enabled: false, mappings: {} };
if (this.options.useMappingProxy) {
urlMapping.enabled = true;
urlMapping.mappings = {
"acme-v02.api.letsencrypt.org": "letsencrypt.proxy.handsfree.work",
};
}
const client = new acme.Client({
directoryUrl: directoryUrl,
accountKey: conf.key,
@@ -69,6 +81,7 @@ export class AcmeService {
backoffAttempts: 30,
backoffMin: 5000,
backoffMax: 10000,
urlMapping,
});
if (conf.accountUrl == null) {

View File

@@ -33,6 +33,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
vModel: "value",
options: [
{ value: "letsencrypt", label: "Let's Encrypt" },
// { value: "letsencrypt-proxy", label: "Let's Encrypt代理letsencrypt.org无法访问时使用" },
// { value: "buypass", label: "Buypass" },
{ value: "zerossl", label: "ZeroSSL" },
],
@@ -79,6 +80,17 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
})
dnsProviderAccess!: string;
@TaskInput({
title: "使用代理",
default: false,
component: {
name: "a-switch",
vModel: "checked",
},
helper: "如果acme-v02.api.letsencrypt.org被墙无法连接访问请尝试开启此选项",
})
useProxy = false;
@TaskInput({
title: "跳过本地校验DNS",
default: false,
@@ -103,6 +115,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
sslProvider: this.sslProvider,
eab,
skipLocalVerify: this.skipLocalVerify,
useMappingProxy: this.useProxy,
});
}

View File

@@ -0,0 +1 @@
export const dnsList = [];

View File

@@ -1,9 +1,9 @@
import { IsTaskPlugin, pluginGroups, RunStrategy, sp, Step, TaskInput } from "@certd/pipeline";
import type { CertInfo } from "./acme.js";
import { CertReader } from "./cert-reader.js";
import { CertApplyBasePlugin } from "./base.js";
import type { CertInfo } from "../acme.js";
import { CertReader } from "../cert-reader.js";
import { CertApplyBasePlugin } from "../base.js";
import fs from "fs";
import { EabAccess } from "../../access";
import { EabAccess } from "../../../access/index.js";
import path from "path";
export { CertReader };
@@ -25,6 +25,21 @@ export type { CertInfo };
},
})
export class CertApplyLegoPlugin extends CertApplyBasePlugin {
// @TaskInput({
// title: "ACME服务端点",
// default: "https://acme-v02.api.letsencrypt.org/directory",
// component: {
// name: "a-select",
// vModel: "value",
// options: [
// { value: "https://acme-v02.api.letsencrypt.org/directory", label: "Let's Encrypt" },
// { value: "https://letsencrypt.proxy.handsfree.work/directory", label: "Let's Encrypt代理letsencrypt.org无法访问时使用" },
// ],
// },
// required: true,
// })
acmeServer!: string;
@TaskInput({
title: "DNS类型",
component: {
@@ -110,8 +125,14 @@ export class CertApplyLegoPlugin extends CertApplyBasePlugin {
const savePathArgs = `--path "${saveDir}"`;
const os_type = process.platform === "win32" ? "windows" : "linux";
const legoPath = path.resolve("./tools", os_type, "lego");
let serverArgs = "";
if (this.acmeServer) {
serverArgs = ` --server ${this.acmeServer}`;
}
const cmds = [
`${legoPath} -a --email "${this.email}" --dns ${this.dnsType} ${keyType} ${domainArgs} ${eabArgs} ${savePathArgs} ${this.customArgs || ""} run`,
`${legoPath} -a --email "${this.email}" --dns ${this.dnsType} ${keyType} ${domainArgs} ${serverArgs} ${eabArgs} ${savePathArgs} ${
this.customArgs || ""
} run`,
];
await sp.spawn({

View File

@@ -1,2 +1,2 @@
export * from "./cert-plugin/index.js";
export * from "./cert-plugin/lego.js";
export * from "./cert-plugin/lego/index.js";

View File

@@ -1,21 +1,21 @@
FROM registry.cn-shenzhen.aliyuncs.com/handsfree/node:18-alpine as builder
FROM node:18-alpine AS builder
EXPOSE 7001
WORKDIR /workspace/
RUN npm install -g pnpm@8.15.7 --registry=https://registry.npmmirror.com
RUN pnpm config set registry https://registry.npmmirror.com/
COPY . /workspace/
RUN npm install -g pnpm@8.15.7
RUN cd /workspace/certd-client && pnpm install && npm run build
#RUN cd /workspace/certd-client && pnpm install && npm run build
RUN cp /workspace/certd-client/dist/* /workspace/certd-server/public/ -rf
RUN cd /workspace/certd-server && pnpm install && npm run build-on-docker
RUN cp /workspace/certd-client/dist/* /workspace/certd-server/public/ -rf
FROM registry.cn-shenzhen.aliyuncs.com/handsfree/node:18-alpine
FROM node:18-alpine
WORKDIR /app/
COPY --from=builder /workspace/certd-server/ /app/
ENV TZ Asia/Shanghai
ENV NODE_ENV production
ENV MIDWAY_SERVER_ENV production
RUN chmod +x /app/tools/linux/*
ENV TZ=Asia/Shanghai
ENV NODE_ENV=production
ENV MIDWAY_SERVER_ENV=production
CMD ["npm", "run","start"]

View File

@@ -3,6 +3,20 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.22.5](https://github.com/certd/certd/compare/v1.22.4...v1.22.5) (2024-07-26)
**Note:** Version bump only for package @certd/ui-client
## [1.22.3](https://github.com/certd/certd/compare/v1.22.2...v1.22.3) (2024-07-25)
**Note:** Version bump only for package @certd/ui-client
## [1.22.2](https://github.com/certd/certd/compare/v1.22.1...v1.22.2) (2024-07-23)
### Bug Fixes
* 修复创建流水线时无法根据dns类型默认正确的dns授权的bug ([a2c43b5](https://github.com/certd/certd/commit/a2c43b50a6069ed48958fd142844a8568c2af452))
## [1.22.1](https://github.com/certd/certd/compare/v1.22.0...v1.22.1) (2024-07-20)
### Performance Improvements

View File

@@ -1,6 +1,6 @@
{
"name": "@certd/ui-client",
"version": "1.22.1",
"version": "1.22.5",
"private": true,
"scripts": {
"dev": "vite --open",
@@ -24,8 +24,6 @@
"dependencies": {
"@ant-design/colors": "^7.0.2",
"@ant-design/icons-vue": "^7.0.1",
"@aws-sdk/client-s3": "^3.535.0",
"@aws-sdk/s3-request-presigner": "^3.535.0",
"@fast-crud/fast-crud": "^1.21.1",
"@fast-crud/fast-extends": "^1.21.1",
"@fast-crud/ui-antdv4": "^1.21.1",
@@ -59,7 +57,7 @@
"vuedraggable": "^2.24.3"
},
"devDependencies": {
"@certd/pipeline": "^1.22.1",
"@certd/pipeline": "^1.22.5",
"@rollup/plugin-commonjs": "^25.0.7",
"@rollup/plugin-node-resolve": "^15.2.3",
"@types/chai": "^4.3.12",

View File

@@ -2,7 +2,7 @@ import _ from "lodash-es";
function copyList(originList: any, newList: any, options: any, parentId?: any) {
for (const item of originList) {
const newItem: any = _.cloneDeep(item);
if(parentId!= null && newItem.parentId == null){
if (parentId != null && newItem.parentId == null) {
newItem.parentId = parentId;
}
@@ -228,7 +228,7 @@ const mockUtil: any = {
handle(req: any): any {
const item = findById(req.body.id, list);
if (item) {
_.mergeWith(item, req.body, (objValue, srcValue) => {
_.mergeWith(item, req.body, (objValue: any, srcValue: any) => {
if (srcValue == null) {
return;
}
@@ -305,7 +305,7 @@ const mockUtil: any = {
console.log("req", req);
let item = findById(req.body.id, list);
if (item) {
_.mergeWith(item, { [req.body.key]: req.body.value }, (objValue, srcValue) => {
_.mergeWith(item, { [req.body.key]: req.body.value }, (objValue: any, srcValue: any) => {
if (srcValue == null) {
return;
}
@@ -336,7 +336,7 @@ const mockUtil: any = {
for (const item of req.body) {
const item2 = findById(item.id, list);
if (item2) {
_.mergeWith(item2, item, (objValue, srcValue) => {
_.mergeWith(item2, item, (objValue: any, srcValue: any) => {
if (srcValue == null) {
return;
}

View File

@@ -13,10 +13,10 @@ const list: any = [];
_.forEach(commonMocks, (value: any) => {
list.push(value.default);
});
_.forEach(apiMocks, (value) => {
_.forEach(apiMocks, (value: any) => {
list.push(value.default);
});
_.forEach(viewMocks, (value) => {
_.forEach(viewMocks, (value: any) => {
list.push(value.default);
});

View File

@@ -1,15 +1,37 @@
import { request, requestForMock } from "/src/api/service";
// import "/src/mock";
import { ColumnCompositionProps, CrudOptions, FastCrud, PageQuery, PageRes, setLogger, TransformResProps, useColumns, UseCrudProps, UserPageQuery, useTypes, utils } from "@fast-crud/fast-crud";
import {
ColumnCompositionProps,
CrudOptions,
FastCrud,
PageQuery,
PageRes,
setLogger,
TransformResProps,
useColumns,
UseCrudProps,
UserPageQuery,
useTypes,
utils
} from "@fast-crud/fast-crud";
import "@fast-crud/fast-crud/dist/style.css";
import { FsExtendsCopyable, FsExtendsEditor, FsExtendsJson, FsExtendsTime, FsExtendsUploader, FsExtendsInput, FsUploaderS3SignedUrlType, FsUploaderGetAuthContext, FsUploaderAliossSTS } from "@fast-crud/fast-extends";
import {
FsExtendsCopyable,
FsExtendsEditor,
FsExtendsJson,
FsExtendsTime,
FsExtendsUploader,
FsExtendsInput,
FsUploaderS3SignedUrlType,
FsUploaderGetAuthContext,
FsUploaderAliossSTS
} from "@fast-crud/fast-extends";
import "@fast-crud/fast-extends/dist/style.css";
import UiAntdv from "@fast-crud/ui-antdv4";
import "@fast-crud/ui-antdv4/dist/style.css";
import _ from "lodash-es";
import { useCrudPermission } from "../permission";
import { App } from "vue";
import { GetSignedUrl } from "/@/views/crud/component/uploader/s3/api";
import { notification } from "ant-design-vue";
function install(app: App, options: any = {}) {
@@ -149,6 +171,7 @@ function install(app: App, options: any = {}) {
// fast-extends里面的扩展组件均为异步组件只有在使用时才会被加载并不会影响首页加载速度
//安装uploader 公共参数
// @ts-ignore
app.use(FsExtendsUploader, {
// @ts-ignore
defaultType: "cos",
@@ -231,33 +254,6 @@ function install(app: App, options: any = {}) {
},
domain: "http://d2p.file.handsfree.work/"
},
s3: {
keepName: true,
//同时也支持minio
bucket: "fast-crud",
sdkOpts: {
s3ForcePathStyle: true,
signatureVersion: "v4",
region: "us-east-1",
forcePathStyle: true,
//minio与s3完全适配
endpoint: "https://play.min.io",
credentials: {
//不建议在客户端使用secretAccessKey来上传
accessKeyId: "Q3AM3UQ867SPQQA43P2F", //访问登录名
secretAccessKey: "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG" //访问密码
}
},
//预签名配置,向后端获取上传的预签名连接
async getSignedUrl(bucket: string, key: string, options: any, type: FsUploaderS3SignedUrlType = "put") {
return await GetSignedUrl(bucket, key, type);
},
successHandle(ret: any) {
// 上传完成后可以在此处处理结果修改url什么的
console.log("success handle:", ret);
return ret;
}
},
form: {
keepName: true,
action: "http://www.docmirror.cn:7070/api/upload/form/upload",

View File

@@ -1,784 +0,0 @@
export const crudResources = [
{
title: "CRUD示例",
name: "crud",
path: "/crud",
redirect: "/crud/basis",
meta: {
icon: "ion:apps-sharp"
},
children: [
{
title: "debug",
name: "debug",
path: "/crud/debug",
component: "/crud/debug/index.vue",
meta: {
isMenu: false
}
},
{
title: "基本特性",
name: "basis",
path: "/crud/basis",
redirect: "/crud/basis/i18n",
meta: {
icon: "ion:disc-outline"
},
children: [
{
title: "FirstDemo",
name: "FsCrudFirst",
path: "/crud/basis/first",
component: "/crud/basis/first/index.vue"
},
{
title: "HelloWorld",
name: "FsCrudHelloWorld",
path: "/crud/basis/helloworld",
component: "/crud/basis/helloworld/index.vue"
},
{
title: "动态计算",
name: "BasisCompute",
path: "/crud/basis/compute",
component: "/crud/basis/compute/index.vue"
},
{
title: "动态计算-更多示例",
name: "BasisComputeMore",
path: "/crud/basis/compute-more",
component: "/crud/basis/compute-more/index.vue"
},
{
title: "国际化",
name: "BasisI18n",
path: "/crud/basis/i18n",
component: "/crud/basis/i18n/index.vue"
},
{
title: "ValueChange",
name: "BasisValueChange",
path: "/crud/basis/value-change",
component: "/crud/basis/value-change/index.vue"
},
{
title: "Card布局",
name: "BasisLayoutCard",
path: "/crud/basis/layout-card",
component: "/crud/basis/layout-card/index.vue"
},
{
title: "自定义布局",
name: "BasisLayoutCustom",
path: "/crud/basis/layout-custom",
component: "/crud/basis/layout-custom/index.vue"
},
{
title: "自定义组件",
name: "BasisCustom",
path: "/crud/basis/custom",
component: "/crud/basis/custom/index.vue"
},
{
title: "列设置",
name: "BasisColumnsSet",
path: "/crud/basis/columns-set",
component: "/crud/basis/columns-set/index.vue"
},
{
title: "字段合并插件",
name: "BasisColumnMergePlugin",
path: "/crud/basis/column-merge-plugin",
component: "/crud/basis/column-merge-plugin/index.vue"
},
{
title: "ResetCrudOptions",
name: "BasisReset",
path: "/crud/basis/reset",
component: "/crud/basis/reset/index.vue",
meta: {
cache: true
}
},
{
title: "CrudOptions插件",
name: "BasisPlugin",
path: "/crud/basis/plugin",
component: "/crud/basis/plugin/index.vue"
},
{
title: "Ts定义测试",
name: "BasisTsTest",
path: "/crud/basis/ts",
component: "/crud/basis/ts/index.vue"
}
]
},
{
title: "数据字典",
name: "dict",
path: "/crud/dict",
redirect: "/crud/dict/single",
meta: {
icon: "ion:book-outline"
},
children: [
{
title: "单例",
name: "DictSingle",
path: "/crud/dict/single",
component: "/crud/dict/single/index.vue"
},
{
title: "分发复制",
name: "DictCloneable",
path: "/crud/dict/cloneable",
component: "/crud/dict/cloneable/index.vue"
},
{
title: "原型复制",
name: "DictPrototype",
path: "/crud/dict/prototype",
component: "/crud/dict/prototype/index.vue"
},
{
title: "页面间共享",
name: "DictShared",
path: "/crud/dict/shared",
children: [
{
title: "共享字典数据管理",
name: "DictSharedManager",
path: "/crud/dict/shared/manager",
component: "/crud/dict/shared/manager/index.vue"
},
{
title: "共享字典使用",
name: "DictSharedUse",
path: "/crud/dict/shared/use",
component: "/crud/dict/shared/use/index.vue"
}
]
}
]
},
{
title: "操作列",
name: "row-handle",
path: "/crud/row-handle",
redirect: "/crud/row-handle/tooltip",
meta: {
icon: "ion:build-outline"
},
children: [
{
title: "Tooltip",
name: "RowHandleTooltip",
path: "/crud/row-handle/tooltip",
component: "/crud/row-handle/tooltip/index.vue"
},
{
title: "按钮折叠",
name: "RowHandleDropdown",
path: "/crud/row-handle/dropdown",
component: "/crud/row-handle/dropdown/index.vue"
}
]
},
{
title: "组件示例",
name: "component",
path: "/crud/component",
redirect: "/crud/component/text",
meta: {
icon: "ion:cube-outline"
},
children: [
{
title: "文本输入(input)",
name: "ComponentText",
path: "/crud/component/text",
component: "/crud/component/text/index.vue"
},
{
title: "选择(select)",
name: "ComponentSelect",
path: "/crud/component/select",
component: "/crud/component/select/index.vue"
},
{
title: " 表格选择(table-select)",
name: "ComponentTableSelect",
path: "/crud/component/table-select",
component: "/crud/component/table-select/index.vue"
},
{
title: "级联(cascader)",
name: "ComponentCascader",
path: "/crud/component/cascader",
component: "/crud/component/cascader/index.vue"
},
{
title: "多选(checkbox)",
name: "ComponentCheckbox",
path: "/crud/component/checkbox",
component: "/crud/component/checkbox/index.vue"
},
{
title: "单选(radio)",
name: "ComponentRadio",
path: "/crud/component/radio",
component: "/crud/component/radio/index.vue"
},
{
title: "开关(switch)",
name: "ComponentSwitch",
path: "/crud/component/switch",
component: "/crud/component/switch/index.vue"
},
{
title: "日期时间(date)",
name: "ComponentDate",
path: "/crud/component/date",
component: "/crud/component/date/index.vue"
},
{
title: "按钮链接",
name: "ComponentButton",
path: "/crud/component/button",
component: "/crud/component/button/index.vue"
},
{
title: "数字",
name: "ComponentNumber",
path: "/crud/component/number",
component: "/crud/component/number/index.vue"
},
{
title: "树形选择",
name: "ComponentTree",
path: "/crud/component/tree",
component: "/crud/component/tree/index.vue"
},
{
title: "图片裁剪上传",
name: "ComponentUploaderCropper",
path: "/crud/component/uploader/cropper",
component: "/crud/component/uploader/cropper/index.vue"
},
{
title: "表单本地上传",
name: "ComponentUploaderForm",
path: "/crud/component/uploader/form",
component: "/crud/component/uploader/form/index.vue"
},
{
title: "阿里云oss上传",
name: "ComponentUploaderAlioss",
path: "/crud/component/uploader/alioss",
component: "/crud/component/uploader/alioss/index.vue"
},
{
title: "腾讯云cos上传",
name: "ComponentUploaderCos",
path: "/crud/component/uploader/cos",
component: "/crud/component/uploader/cos/index.vue"
},
{
title: "七牛云上传",
name: "ComponentUploaderQiniu",
path: "/crud/component/uploader/qiniu",
component: "/crud/component/uploader/qiniu/index.vue"
},
{
title: "s3上传",
name: "ComponentUploaderS3",
path: "/crud/component/uploader/s3",
component: "/crud/component/uploader/s3/index.vue"
},
{
title: "富文本编辑器",
name: "ComponentEditor",
path: "/crud/component/editor",
component: "/crud/component/editor/index.vue"
},
{
title: "图标",
name: "ComponentIcon",
path: "/crud/component/icon",
component: "/crud/component/icon/index.vue"
},
{
title: "JsonEditor",
name: "ComponentJson",
path: "/crud/component/json",
component: "/crud/component/json/index.vue"
},
{
title: "手机号输入框",
name: "ComponentPhone",
path: "/crud/component/phone",
component: "/crud/component/phone/index.vue"
},
{
title: "组件独立使用",
name: "ComponentIndependent",
path: "/crud/component/independent",
component: "/crud/component/independent/index.vue"
}
]
},
{
title: "Form表单",
name: "form",
path: "/crud/form",
redirect: "/crud/form/layout",
meta: {
icon: "ion:document-text-outline"
},
children: [
{
title: "基本表单",
name: "FormBase",
path: "/crud/form/base",
component: "/crud/form/base/index.vue"
},
{
title: "表单Grid布局",
name: "FormLayoutGrid",
path: "/crud/form/layout-grid",
component: "/crud/form/layout-grid/index.vue"
},
{
title: "表单Flex布局",
name: "FormLayoutFlex",
path: "/crud/form/layout-flex",
component: "/crud/form/layout-flex/index.vue"
},
{
title: "表单动态布局",
name: "FormLayout",
path: "/crud/form/layout",
component: "/crud/form/layout/index.vue"
},
{
title: "表单单列模式",
name: "FormSingleColumn",
path: "/crud/form/single-column",
component: "/crud/form/single-column/index.vue"
},
{
title: "表单校验",
name: "FormValidation",
path: "/crud/form/validation",
component: "/crud/form/validation/index.vue"
},
{
title: "抽屉表单",
name: "FormDrawer",
path: "/crud/form/drawer",
component: "/crud/form/drawer/index.vue"
},
{
title: "表单分组",
name: "FormGroup",
path: "/crud/form/group",
component: "/crud/form/group/index.vue"
},
{
title: "表单分组(tabs)",
name: "FormGroupTabs",
path: "/crud/form/group-tabs",
component: "/crud/form/group-tabs/index.vue"
},
{
title: "自定义表单",
name: "FormCustomForm",
path: "/crud/form/custom-form",
component: "/crud/form/custom-form/index.vue"
},
{
title: "字段帮助说明",
name: "FormHelper",
path: "/crud/form/helper",
component: "/crud/form/helper/index.vue"
},
{
title: "页面内部弹出表单",
name: "FormInner",
path: "/crud/form/inner",
component: "/crud/form/inner/index.vue",
meta: {
cache: true
}
},
{
title: "地区字典管理",
name: "FormInnerArea",
path: "/crud/form/inner/area",
component: "/crud/form/inner/area/index.vue",
meta: {
isMenu: false
}
},
{
title: "新页面编辑",
name: "FormNewPage",
path: "/crud/form/new-page",
component: "/crud/form/new-page/index.vue",
meta: {
cache: false
}
},
{
title: "新页面编辑表单",
name: "FormNewPageEdit",
path: "/crud/form/new-page/edit",
component: "/crud/form/new-page/edit.vue",
meta: {
isMenu: false
}
},
{
title: "独立使用表单",
name: "FormIndependent",
path: "/crud/form/independent",
component: "/crud/form/independent/index.vue"
},
{
title: "重置表单",
name: "FormReset",
path: "/crud/form/reset",
component: "/crud/form/reset/index.vue"
},
{
title: "嵌套数据结构",
name: "FormNest",
path: "/crud/form/nest",
component: "/crud/form/nest/index.vue"
},
{
title: "字段组件render",
name: "FormRender",
path: "/crud/form/render",
component: "/crud/form/render/index.vue"
},
{
title: "查看表单使用单元格组件",
name: "FormView",
path: "/crud/form/view",
component: "/crud/form/view/index.vue"
},
{
title: "initialForm",
name: "FormInitial",
path: "/crud/form/initial",
component: "/crud/form/initial/index.vue"
},
{
title: "表单Watch",
name: "FormWatch",
path: "/crud/form/watch",
component: "/crud/form/watch/index.vue"
}
]
},
{
title: "表格特性",
path: "/crud/feature",
meta: {
icon: "ion:beer-outline"
},
redirect: "/crud/feature/dropdown",
children: [
{
title: "部件显隐",
name: "FeatureHide",
path: "/crud/feature/hide",
component: "/crud/feature/hide/index.vue"
},
{
title: "多选&批量删除",
name: "FeatureSelection",
path: "/crud/feature/selection",
component: "/crud/feature/selection/index.vue"
},
{
title: "单选",
name: "FeatureSelectionRadio",
path: "/crud/feature/selection-radio",
component: "/crud/feature/selection-radio/index.vue"
},
{
title: "表头过滤",
name: "FeatureFilter",
path: "/crud/feature/filter",
component: "/crud/feature/filter/index.vue"
},
{
title: "行展开",
name: "FeatureExpand",
path: "/crud/feature/expand",
component: "/crud/feature/expand/index.vue"
},
{
title: "树形表格",
name: "FeatureTree",
path: "/crud/feature/tree",
component: "/crud/feature/tree/index.vue"
},
{
title: "多级表头",
name: "FeatureHeaderGroup",
path: "/crud/feature/header-group",
component: "/crud/feature/header-group/index.vue"
},
{
title: "自定义表头",
name: "FeatureHeader",
path: "/crud/feature/header",
component: "/crud/feature/header/index.vue"
},
{
title: "合并单元格",
name: "FeatureMerge",
path: "/crud/feature/merge",
component: "/crud/feature/merge/index.vue"
},
{
title: "序号",
name: "FeatureIndex",
path: "/crud/feature/index",
component: "/crud/feature/index/index.vue"
},
{
title: "排序",
name: "FeatureSortable",
path: "/crud/feature/sortable",
component: "/crud/feature/sortable/index.vue"
},
{
title: "固定列",
name: "FeatureFixed",
path: "/crud/feature/fixed",
component: "/crud/feature/fixed/index.vue"
},
{
title: "不固定高度",
name: "FeatureHeight",
path: "/crud/feature/height",
component: "/crud/feature/height/index.vue"
},
{
title: "查询框",
name: "FeatureSearch",
path: "/crud/feature/search",
component: "/crud/feature/search/index.vue"
},
{
title: "查询框多行模式",
name: "FeatureSearchMulti",
path: "/crud/feature/search-multi",
component: "/crud/feature/search-multi/index.vue"
},
{
title: "Tabs快捷查询",
name: "FeatureTabs",
path: "/crud/feature/tabs",
component: "/crud/feature/tabs/index.vue"
},
{
title: "字段排序",
name: "FeatureColumnSort",
path: "/crud/feature/column-sort",
component: "/crud/feature/column-sort/index.vue"
},
{
title: "ValueBuilder",
name: "FeatureValueBuilder",
path: "/crud/feature/value-builder",
component: "/crud/feature/value-builder/index.vue"
},
{
title: "列设置",
name: "FeatureColumnsSet",
path: "/crud/feature/columns-set",
component: "/crud/feature/columns-set/index.vue"
},
{
title: "本地化编辑",
name: "FeatureLocal",
path: "/crud/feature/local",
component: "/crud/feature/local/index.vue"
},
{
title: "v-model",
name: "FeatureVModel",
path: "/crud/feature/local-v-model",
component: "/crud/feature/local-v-model/index.vue"
},
{
title: "导入",
name: "FeatureImport",
path: "/crud/feature/local-import",
component: "/crud/feature/local-import/index.vue"
},
{
title: "导出",
name: "FeatureExport",
path: "/crud/feature/export",
component: "/crud/feature/export/index.vue"
},
{
title: "自定义删除",
name: "FeatureRemove",
path: "/crud/feature/remove",
component: "/crud/feature/remove/index.vue"
},
{
title: "调整列宽",
name: "FeatureColumnResize",
path: "/crud/feature/column-resize",
component: "/crud/feature/column-resize/index.vue"
}
]
},
{
title: "可编辑",
name: "Editable",
path: "/crud/editable",
redirect: "/crud/editable/free",
meta: {
icon: "ion:create-outline"
},
children: [
{
title: "自由编辑",
name: "EditableFree",
path: "/crud/editable/free",
component: "/crud/editable/free/index.vue"
},
{
title: "行编辑",
name: "EditableRow",
path: "/crud/editable/row",
component: "/crud/editable/row/index.vue"
},
{
title: "单元格编辑",
name: "EditableCell",
path: "/crud/editable/cell",
component: "/crud/editable/cell/index.vue"
},
{
title: "子表格编辑",
name: "EditableVModel",
path: "/crud/editable/vmodel",
component: "/crud/editable/vmodel/index.vue"
},
{
title: "子CRUD",
name: "EditableSubCrud",
path: "/crud/editable/sub-crud",
component: "/crud/editable/sub-crud/index.vue"
}
]
},
{
title: "插槽",
name: "Slots",
path: "/crud/slots",
redirect: "/crud/slots/layout",
meta: {
icon: "ion:extension-puzzle-outline"
},
children: [
{
title: "页面占位插槽",
name: "SlotsLayout",
path: "/crud/slots/layout",
component: "/crud/slots/layout/index.vue"
},
{
title: "表单占位插槽",
name: "SlotsForm",
path: "/crud/slots/form",
component: "/crud/slots/form/index.vue"
},
{
title: "查询字段插槽",
name: "SlotsSearch",
path: "/crud/slots/search",
component: "/crud/slots/search/index.vue"
},
{
title: "单元格插槽",
name: "SlotsCell",
path: "/crud/slots/cell",
component: "/crud/slots/cell/index.vue"
},
{
title: "表单字段插槽",
name: "SlotsFormItem",
path: "/crud/slots/form-item",
component: "/crud/slots/form-item/index.vue"
}
]
},
{
title: "复杂需求",
name: "Advanced",
path: "/crud/advanced",
redirect: "/crud/advanced/linkage",
meta: {
icon: "ion:flame-outline"
},
children: [
{
title: "选择联动",
name: "AdvancedLinkage",
path: "/crud/advanced/linkage",
component: "/crud/advanced/linkage/index.vue"
},
{
title: "后台加载crud",
name: "AdvancedFormBackend",
path: "/crud/advanced/from-backend",
component: "/crud/advanced/from-backend/index.vue"
},
{
title: "本地分页",
name: "AdvancedLocalPagination",
path: "/crud/advanced/local-pagination",
component: "/crud/advanced/local-pagination/index.vue"
},
{
title: "嵌套子表格",
name: "AdvancedNest",
path: "/crud/advanced/nest",
component: "/crud/advanced/nest/index.vue"
},
{
title: "对话框中显示crud",
name: "AdvancedInDialog",
path: "/crud/advanced/in-dialog",
component: "/crud/advanced/in-dialog/index.vue"
},
{
title: "抽屉中显示crud",
name: "AdvancedInDrawer",
path: "/crud/advanced/in-drawer",
component: "/crud/advanced/in-drawer/index.vue"
},
{
title: "大量数据",
name: "AdvancedBigData",
path: "/crud/advanced/big-data",
component: "/crud/advanced/big-data/index.vue"
}
]
}
]
}
];

View File

@@ -1,22 +0,0 @@
export const integrationResources = [
{
title: "集成",
name: "integration",
path: "/integration",
redirect: "/integration/bpmn",
meta: {
icon: "ion:apps-sharp"
},
children: [
{
title: "FsBpmn",
name: "FsBpmn",
path: "/integration/bpmn",
component: "/integration/bpmn/index.vue",
meta: {
icon: "ion:disc-outline"
}
}
]
}
];

View File

@@ -1,30 +0,0 @@
export const uiResources = [
{
title: "UI示例",
name: "ui",
path: "/ui",
redirect: "/ui/form",
meta: {
icon: "ion:apps-sharp"
},
children: [
{
title: "表单组件",
name: "UIForm",
path: "/ui/form",
redirect: "/ui/form/input",
meta: {
icon: "ion:disc-outline"
},
children: [
{
title: "input",
name: "UIFormInput",
path: "/ui/form/input",
component: "/ui/form/input/index.vue"
}
]
}
]
}
];

View File

@@ -0,0 +1,19 @@
import _ from "lodash-es";
import { compute } from "@fast-crud/fast-crud";
export function useReference(form: any) {
if (!form.reference) {
return;
}
for (const reference of form.reference) {
debugger;
_.set(
form,
reference.dest,
compute<any>((scope) => {
debugger;
return _.get(scope, reference.src);
})
);
}
}

View File

@@ -1,5 +1,7 @@
import { compute, CreateCrudOptionsRet, dict } from "@fast-crud/fast-crud";
import { PluginGroup } from "@certd/pipeline";
import { useReference } from "/@/use/use-refrence";
import _ from "lodash-es";
export default function (certPluginGroup: PluginGroup, formWrapperRef: any): CreateCrudOptionsRet {
const inputs: any = {};
@@ -10,10 +12,11 @@ export default function (certPluginGroup: PluginGroup, formWrapperRef: any): Cre
inputs[inputKey].form.show = true;
continue;
}
const inputDefine = plugin.input[inputKey];
const inputDefine = _.cloneDeep(plugin.input[inputKey]);
if (!inputDefine.required && !inputDefine.maybeNeed) {
continue;
}
useReference(inputDefine);
inputs[inputKey] = {
title: inputDefine.title,
form: {

View File

@@ -1,43 +0,0 @@
import { requestForMock } from "/src/api/service";
const request = requestForMock;
const apiPrefix = "/mock/AdvancedBigData";
export function GetList(query: any) {
return request({
url: apiPrefix + "/page",
method: "get",
data: query
});
}
export function AddObj(obj: any) {
return request({
url: apiPrefix + "/add",
method: "post",
data: obj
});
}
export function UpdateObj(obj: any) {
return request({
url: apiPrefix + "/update",
method: "post",
data: obj
});
}
export function DelObj(id: any) {
return request({
url: apiPrefix + "/delete",
method: "post",
params: { id }
});
}
export function GetObj(id: any) {
return request({
url: apiPrefix + "/get",
method: "get",
params: { id }
});
}

View File

@@ -1,172 +0,0 @@
import * as api from "./api";
import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
export default function ({ crudExpose }: CreateCrudOptionsProps): CreateCrudOptionsRet {
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
return await api.GetList(query);
};
const editRequest = async ({ form, row }: EditReq) => {
if (form.id == null) {
form.id = row.id;
}
return await api.UpdateObj(form);
};
const delRequest = async ({ row }: DelReq) => {
return await api.DelObj(row.id);
};
const addRequest = async ({ form }: AddReq) => {
return await api.AddObj(form);
};
return {
output: {},
crudOptions: {
//大量数据的crud配置
request: {
pageRequest,
addRequest,
editRequest,
delRequest
},
table: {
scroll: {
//启用横向滚动条,设置一个大于所有列宽之和的值,一般大于表格宽度
x: 2400
}
},
pagination: {
pageSize: 100
},
rowHandle: {
fixed: "right"
},
columns: {
id: {
title: "ID",
type: "number",
column: {
width: 50
},
form: {
show: false
}
},
text: {
title: "文本",
type: "text"
},
dict1: {
title: "字典1",
type: "dict-select",
dict: dict({
url: "/mock/dicts/ManyOpenStatusEnum?from=dict1"
})
},
dict2: {
title: "字典2",
type: "dict-select",
dict: dict({
url: "/mock/dicts/ManyOpenStatusEnum?from=dict2"
})
},
dict3: {
title: "字典3",
type: "dict-select",
dict: dict({
url: "/mock/dicts/ManyOpenStatusEnum?from=dict3"
})
},
dict4: {
title: "字典4",
type: "dict-select",
dict: dict({
url: "/mock/dicts/ManyOpenStatusEnum?from=dict4"
})
},
dict5: {
title: "字典5",
type: "dict-select",
dict: dict({
url: "/mock/dicts/ManyOpenStatusEnum?from=dict5"
})
},
dict6: {
title: "字典6",
type: "dict-select",
dict: dict({
url: "/mock/dicts/ManyOpenStatusEnum?from=dict6"
})
},
dict7: {
title: "字典7",
type: "dict-select",
dict: dict({
url: "/mock/dicts/ManyOpenStatusEnum?from=dict7"
})
},
dict8: {
title: "字典8",
type: "dict-select",
dict: dict({
url: "/mock/dicts/ManyOpenStatusEnum?from=dict8"
})
},
dict9: {
title: "字典9",
type: "dict-select",
dict: dict({
url: "/mock/dicts/ManyOpenStatusEnum?from=dict9"
})
},
dict10: {
title: "字典10",
type: "dict-select",
dict: dict({
url: "/mock/dicts/ManyOpenStatusEnum?from=dict10"
})
},
text1: {
title: "文本",
type: "text"
},
text2: {
title: "文本",
type: "text"
},
text3: {
title: "文本",
type: "text"
},
text4: {
title: "文本",
type: "text"
},
text5: {
title: "文本",
type: "text"
},
text6: {
title: "文本",
type: "text"
},
text7: {
title: "文本",
type: "text"
},
text8: {
title: "文本",
type: "text"
},
text9: {
title: "文本",
type: "text"
},
text10: {
title: "文本",
type: "text"
}
}
}
};
}

View File

@@ -1,31 +0,0 @@
<template>
<fs-page>
<template #header>
<div class="title">大量数据</div>
</template>
<fs-crud ref="crudRef" v-bind="crudBinding"> </fs-crud>
</fs-page>
</template>
<script lang="ts">
import { defineComponent, onMounted } from "vue";
import { useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud.js";
export default defineComponent({
name: "AdvancedBigData",
setup() {
const { crudBinding, crudRef, crudExpose, output } = useFs({ createCrudOptions });
// 页面打开后获取列表数据
onMounted(() => {
crudExpose.doRefresh();
});
return {
crudBinding,
crudRef,
...output
};
}
});
</script>

View File

@@ -1,128 +0,0 @@
// @ts-ignore
import mockUtil from "/src/mock/base";
const options: any = {
name: "AdvancedBigData",
idGenerator: 0,
//此处copy多次模拟大量数据
copyTimes: 1000
};
const list = [
{
text: "测试文本",
dict1: "1",
dict2: "1",
dict3: "2",
dict4: "1",
dict5: "2",
dict6: "1",
dict7: "1",
dict8: "1",
text1: "测试文本1",
text2: "测试文本2",
text3: "测试文本3",
text4: "测试文本4",
text5: "测试文本5",
text6: "测试文本6",
text7: "测试文本7",
text8: "测试文本8",
dict9: "2",
dict10: "1",
dict11: "2",
dict12: "1"
},
{
text: "测试文本",
dict1: "1",
dict2: "1",
dict3: "2",
dict4: "1",
dict5: "2",
dict6: "1",
dict7: "1",
dict8: "1",
text1: "测试文本1",
text2: "测试文本2",
text3: "测试文本3",
text4: "测试文本4",
text5: "测试文本5",
text6: "测试文本6",
text7: "测试文本7",
text8: "测试文本8",
dict9: "2",
dict10: "1",
dict11: "2",
dict12: "1"
},
{
text: "测试文本",
dict1: "1",
dict2: "1",
dict3: "2",
dict4: "1",
dict5: "2",
dict6: "1",
dict7: "1",
dict8: "1",
text1: "测试文本1",
text2: "测试文本2",
text3: "测试文本3",
text4: "测试文本4",
text5: "测试文本5",
text6: "测试文本6",
text7: "测试文本7",
text8: "测试文本8",
dict9: "2",
dict10: "1",
dict11: "2",
dict12: "1"
},
{
text: "测试文本",
dict1: "1",
dict2: "1",
dict3: "2",
dict4: "1",
dict5: "2",
dict6: "1",
dict7: "1",
dict8: "1",
text1: "测试文本1",
text2: "测试文本2",
text3: "测试文本3",
text4: "测试文本4",
text5: "测试文本5",
text6: "测试文本6",
text7: "测试文本7",
text8: "测试文本8",
dict9: "2",
dict10: "1",
dict11: "2",
dict12: "1"
},
{
text: "测试文本",
dict1: "1",
dict2: "1",
dict3: "2",
dict4: "1",
dict5: "2",
dict6: "1",
dict7: "1",
dict8: "1",
text1: "测试文本1",
text2: "测试文本2",
text3: "测试文本3",
text4: "测试文本4",
text5: "测试文本5",
text6: "测试文本6",
text7: "测试文本7",
text8: "测试文本8",
dict9: "2",
dict10: "1",
dict11: "2",
dict12: "1"
}
];
options.list = list;
const mock = mockUtil.buildMock(options);
export default mock;

View File

@@ -1,48 +0,0 @@
import { requestForMock } from "/src/api/service";
const request = requestForMock;
const apiPrefix = "/mock/AdvancedFromBackend";
export function GetList(query: any) {
return request({
url: apiPrefix + "/page",
method: "get",
data: query
});
}
export function AddObj(obj: any) {
return request({
url: apiPrefix + "/add",
method: "post",
data: obj
});
}
export function UpdateObj(obj: any) {
return request({
url: apiPrefix + "/update",
method: "post",
data: obj
});
}
export function DelObj(id: any) {
return request({
url: apiPrefix + "/delete",
method: "post",
params: { id }
});
}
export function GetObj(id: any) {
return request({
url: apiPrefix + "/get",
method: "get",
params: { id }
});
}
export function GetCrud() {
return request({
url: apiPrefix + "/crud",
method: "get"
});
}

View File

@@ -1,30 +0,0 @@
//此处演示从后台获取crudOptions配置字符串
export const crudOptions = `
({crudExpose,dict}) => {
return {
columns: {
id: {
title: "ID",
key: "id",
type: "number",
column: {
width: 50
},
form: {
show: false
}
},
radio: {
title: "状态",
search: { show: true },
type: "dict-radio",
dict: dict({
url: "/mock/dicts/OpenStatusEnum?single"
})
}
}
}
}
`;

View File

@@ -1,51 +0,0 @@
import * as api from "./api";
import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, EditReq, UserPageQuery, UserPageRes, dict } from "@fast-crud/fast-crud";
import { GetCrud } from "./api";
import _ from "lodash-es";
/**
* 异步创建options
* @param props
*/
export default async function (props: CreateCrudOptionsProps): Promise<CreateCrudOptionsRet> {
const { crudExpose } = props;
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
return await api.GetList(query);
};
const editRequest = async ({ form, row }: EditReq) => {
if (form.id == null) {
form.id = row.id;
}
return await api.UpdateObj(form);
};
const delRequest = async ({ row }: DelReq) => {
return await api.DelObj(row.id);
};
const addRequest = async ({ form }: AddReq) => {
return await api.AddObj(form);
};
const localCrudOptions = {
request: {
pageRequest,
addRequest,
editRequest,
delRequest
}
};
// 上面是本地crudOptions
// 下面从后台获取crudOptions
const ret = await GetCrud();
// 编译
const crudBackend = eval(ret);
// 本示例返回的是一个方法字符串所以要先执行这个方法获取options
const remoteCrudOptions = crudBackend({ crudExpose, dict });
// 与本地options合并
const crudOptions = _.merge(localCrudOptions, remoteCrudOptions);
return {
crudOptions
};
}

View File

@@ -1,44 +0,0 @@
<template>
<fs-page>
<template #header>
<div class="title">CrudOptions从后台加载</div>
<div class="more">
<a target="_blank" href="http://fast-crud.docmirror.cn/api/use.html#usefsasync">文档</a>
</div>
</template>
<fs-crud v-if="crudBinding" ref="crudRef" v-bind="crudBinding" />
</fs-page>
</template>
<script lang="ts">
import { defineComponent, onMounted, ref, Ref } from "vue";
import { CrudBinding, useFsAsync } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud";
export default defineComponent({
name: "AdvancedFromBackend",
setup() {
// crud组件的ref
const crudRef: Ref = ref();
// crud 配置的ref
const crudBinding: Ref<CrudBinding> = ref();
const customValue: any = {}; //自定义变量传给createCrudOptions的额外参数
// 初始化crud配置
// 页面打开后获取列表数据
onMounted(async () => {
const customValue = {};
//异步初始化fscreateCrudOptions为异步方法
const { crudExpose, context } = await useFsAsync({ crudRef, crudBinding, createCrudOptions, context: customValue });
// 刷新数据
await crudExpose.doRefresh();
});
return {
crudBinding,
crudRef
};
}
});
</script>

View File

@@ -1,36 +0,0 @@
// @ts-ignore
import mockUtil from "/src/mock/base";
import { crudOptions } from "./crud-backend";
const options: any = {
name: "AdvancedFromBackend",
idGenerator: 0
};
const list = [
{
radio: "1"
},
{
radio: "2"
},
{
radio: "0"
}
];
options.list = list;
options.copyTimes = 1000;
const mock = mockUtil.buildMock(options);
mock.push({
path: "/AdvancedFromBackend/crud",
method: "get",
handle(req: any) {
return {
code: 0,
msg: "success",
data: crudOptions
};
}
});
export default mock;

View File

@@ -1,42 +0,0 @@
import { requestForMock } from "/src/api/service";
const request = requestForMock;
const apiPrefix = "/mock/AdvancedInDialog";
export function GetList(query: any) {
return request({
url: apiPrefix + "/page",
method: "get",
data: query
});
}
export function AddObj(obj: any) {
return request({
url: apiPrefix + "/add",
method: "post",
data: obj
});
}
export function UpdateObj(obj: any) {
return request({
url: apiPrefix + "/update",
method: "post",
data: obj
});
}
export function DelObj(id: any) {
return request({
url: apiPrefix + "/delete",
method: "post",
params: { id }
});
}
export function GetObj(id: any) {
return request({
url: apiPrefix + "/get",
method: "get",
params: { id }
});
}

View File

@@ -1,115 +0,0 @@
import * as api from "./api";
import {
AddReq,
CreateCrudOptionsProps,
CreateCrudOptionsRet,
DelReq,
EditReq,
UserPageQuery,
UserPageRes,
dict,
utils
} from "@fast-crud/fast-crud";
import { SearchOutlined } from "@ant-design/icons-vue";
export default function ({ crudExpose }: CreateCrudOptionsProps): CreateCrudOptionsRet {
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
return await api.GetList(query);
};
const editRequest = async ({ form, row }: EditReq) => {
if (form.id == null) {
form.id = row.id;
}
return await api.UpdateObj(form);
};
const delRequest = async ({ row }: DelReq) => {
return await api.DelObj(row.id);
};
const addRequest = async ({ form }: AddReq) => {
return await api.AddObj(form);
};
return {
crudOptions: {
request: {
pageRequest,
addRequest,
editRequest,
delRequest
},
columns: {
name: {
title: "姓名",
type: "text", //虽然不写也能正确显示组件,但不建议省略它
search: { show: true },
form: {
component: {
maxlength: 20
}
}
},
search: {
title: "搜索",
type: "text",
form: {
component: {
addonAfter: "后置",
suffix: "suffix",
children: {
addonBefore() {
return <SearchOutlined />;
}
}
}
}
},
password: {
title: "密码",
type: "password",
column: {
//一般密码不显示在列里面
show: false
}
},
intro: {
title: "简介",
type: "textarea",
form: {
component: { showWordLimit: true, maxlength: 200 }
},
column: {
ellipsis: true
}
},
render: {
title: "复杂输入(render)",
type: "text",
form: {
title: "复杂输入",
component: {
render(context: any) {
utils.logger.info("context scope", context);
return (
<a-input-group compact>
<a-input placeholder={"render1 input"} style="width: 50%" v-model={[context.form.render, "value"]} />
<a-input placeholder={"render2 input"} style="width: 50%" v-model={[context.form.render2, "value"]} />
</a-input-group>
);
}
}
}
},
render2: {
title: "我的值是由复杂输入列输入的",
type: "text",
column: {
width: "300px"
},
form: {
show: false
}
}
}
}
};
}

View File

@@ -1,28 +0,0 @@
<template>
<fs-page>
<fs-crud ref="crudRef" v-bind="crudBinding" />
</fs-page>
</template>
<script lang="ts">
import { defineComponent, onMounted } from "vue";
import { useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud";
export default defineComponent({
name: "FsInDialog",
setup() {
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions });
// 页面打开后获取列表数据
onMounted(() => {
crudExpose.doRefresh();
});
return {
crudBinding,
crudRef
};
}
});
</script>

View File

@@ -1,41 +0,0 @@
// @ts-ignore
import mockUtil from "/src/mock/base";
const options: any = {
name: "AdvancedInDialog",
idGenerator: 0
};
const list = [
{
name: "王小虎",
date: "2016-05-02",
status: "0",
province: "1",
avatar: "https://alicdn.antdv.com/vue.png",
show: true,
city: "sz",
address: "123123",
zip: "518000",
intro: "王小虎是element-plus的table示例出现的名字"
},
{
name: "张三",
date: "2016-05-04",
status: "1",
province: "2"
},
{
name: "李四",
date: 2232433534511,
status: "1",
province: "0"
},
{
name: "王五",
date: "2016-05-03",
status: "2",
province: "wh,gz"
}
];
options.list = list;
const mock = mockUtil.buildMock(options);
export default mock;

View File

@@ -1,37 +0,0 @@
<template>
<fs-page>
<template #header>
<div class="title">对话框中显示crud</div>
</template>
<div style="padding: 50px">
<a-button type="primary" @click="openDialog">打开对话框</a-button>
</div>
<a-modal v-model:open="dialogShow" width="80%" title="fs-crud in dialog">
<div style="height: 400px; position: relative">
<!-- 在此处显示fs-crud页面 -->
<fs-in-dialog></fs-in-dialog>
</div>
</a-modal>
</fs-page>
</template>
<script lang="ts">
import { defineComponent, ref } from "vue";
//将fs-crud做成的页面在此处引入
import FsInDialog from "./crud/index.vue";
export default defineComponent({
name: "InDialog",
components: { FsInDialog },
setup() {
const dialogShow = ref(false);
function openDialog() {
dialogShow.value = true;
}
return {
dialogShow,
openDialog
};
}
});
</script>

View File

@@ -1,43 +0,0 @@
//@ts-ignore
import { requestForMock } from "/src/api/service";
const request = requestForMock;
const apiPrefix = "/mock/AdvancedInDrawer";
export function GetList(query: any) {
return request({
url: apiPrefix + "/page",
method: "get",
data: query
});
}
export function AddObj(obj: any) {
return request({
url: apiPrefix + "/add",
method: "post",
data: obj
});
}
export function UpdateObj(obj: any) {
return request({
url: apiPrefix + "/update",
method: "post",
data: obj
});
}
export function DelObj(id: any) {
return request({
url: apiPrefix + "/delete",
method: "post",
params: { id }
});
}
export function GetObj(id: any) {
return request({
url: apiPrefix + "/get",
method: "get",
params: { id }
});
}

View File

@@ -1,76 +0,0 @@
import * as api from "./api";
import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
//从context中获取子组件的ref
const drawerClassTimeRef = context.drawerClassTimeRef;
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
return await api.GetList(query);
};
const editRequest = async ({ form, row }: EditReq) => {
if (form.id == null) {
form.id = row.id;
}
return await api.UpdateObj(form);
};
const delRequest = async ({ row }: DelReq) => {
return await api.DelObj(row.id);
};
const addRequest = async ({ form }: AddReq) => {
return await api.AddObj(form);
};
return {
crudOptions: {
request: {
pageRequest,
addRequest,
editRequest,
delRequest
},
rowHandle: {
width: 300,
buttons: {
editClassTime: {
text: "录入课时",
click: ({ row }) => {
//调用子组件暴露的open方法打开抽屉对话框
drawerClassTimeRef.value.open({
textbook: row
});
}
}
}
},
columns: {
textbookCategory: {
title: "教材分类",
type: "text", //虽然不写也能正确显示组件,但不建议省略它
search: { show: true }
},
textbookVersion: {
title: "教材版本",
type: "text"
},
textbookName: {
title: "教材名称",
type: "text"
},
totalWords: {
title: "总词汇数",
type: "number"
},
classTimeNumber: {
title: "课时数量",
type: "number",
column: {
cellRender({ value }) {
return `${value}课时`;
}
}
}
}
}
};
}

View File

@@ -1,43 +0,0 @@
//@ts-ignore
import { requestForMock } from "/src/api/service";
const request = requestForMock;
const apiPrefix = "/mock/AdvancedInDrawerClassTime";
export function GetList(query: any) {
return request({
url: apiPrefix + "/page",
method: "get",
data: query
});
}
export function AddObj(obj: any) {
return request({
url: apiPrefix + "/add",
method: "post",
data: obj
});
}
export function UpdateObj(obj: any) {
return request({
url: apiPrefix + "/update",
method: "post",
data: obj
});
}
export function DelObj(id: any) {
return request({
url: apiPrefix + "/delete",
method: "post",
params: { id }
});
}
export function GetObj(id: any) {
return request({
url: apiPrefix + "/get",
method: "get",
params: { id }
});
}

View File

@@ -1,89 +0,0 @@
import * as api from "./api";
import { computed } from "vue";
import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
const textbookRef = context.textbookRef;
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
return await api.GetList(query);
};
const editRequest = async ({ form, row }: EditReq) => {
if (form.id == null) {
form.id = row.id;
}
return await api.UpdateObj(form);
};
const delRequest = async ({ row }: DelReq) => {
return await api.DelObj(row.id);
};
const addRequest = async ({ form }: AddReq) => {
return await api.AddObj(form);
};
return {
crudOptions: {
request: {
pageRequest,
addRequest,
editRequest,
delRequest
},
columns: {
textbookId: {
title: "教材ID",
type: "text",
search: {
show: true
},
form: {
value: computed(() => {
//动态设置初始值
return textbookRef.value.id;
})
}
},
textbookCategory: {
title: "教材分类",
type: "text",
form: { show: false },
column: {
//本字段禁止条件render因为此字段没有值是从父组件传过来显示的
conditionalRender: false,
cellRender() {
return textbookRef.value.textbookCategory;
}
}
},
textbookVersion: {
title: "教材版本",
type: "text",
form: { show: false },
column: {
//本字段禁止条件render因为此字段没有值是从父组件传过来显示的
conditionalRender: false,
cellRender() {
return textbookRef.value.textbookVersion;
}
}
},
textbookName: {
title: "教材名称",
type: "text",
form: { show: false },
column: {
//本字段禁止条件render因为此字段没有值是从父组件传过来显示的
conditionalRender: false,
cellRender() {
return textbookRef.value.textbookName;
}
}
},
classTimeName: {
title: "课时名称",
type: "text"
}
}
}
};
}

View File

@@ -1,35 +0,0 @@
<template>
<a-drawer v-model:open="drawerOpened" width="1000px">
<fs-crud ref="crudRef" v-bind="crudBinding"></fs-crud>
</a-drawer>
</template>
<script lang="ts" setup>
import { ref, nextTick } from "vue";
import { useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud";
const textbookRef = ref();
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context: { textbookRef } });
//课时子表组件名称定义
defineOptions({
name: "AdvancedInDrawerClassTime"
});
const drawerOpened = ref(false);
//定义抽屉打开方法
const open = async ({ textbook }) => {
textbookRef.value = textbook;
drawerOpened.value = true;
await nextTick(); //等待crud初始化完成
//设置查询条件只查询当前选中的教材id
crudExpose.setSearchFormData({ form: { textbookId: textbook.id } });
//刷新课时表
await crudExpose.doRefresh();
};
//暴露出去父组件通过ref可以调用open方法
defineExpose({
open
});
</script>

View File

@@ -1,61 +0,0 @@
// @ts-ignore
import mockUtil from "/src/mock/base";
const options: any = {
name: "AdvancedInDrawerClassTime",
idGenerator: 0
};
const list = [
{
textbookId: 1,
classTimeName: "1",
order: 1
},
{
textbookId: 1,
classTimeName: "2",
order: 1
},
{
textbookId: 1,
classTimeName: "3",
order: 1
},
{
textbookId: 1,
classTimeName: "4",
order: 1
},
{
textbookId: 1,
classTimeName: "5",
order: 1
},
{
textbookId: 2,
classTimeName: "1",
order: 1
},
{
textbookId: 2,
classTimeName: "2",
order: 1
},
{
textbookId: 2,
classTimeName: "3",
order: 1
},
{
textbookId: 2,
classTimeName: "4",
order: 1
},
{
textbookId: 2,
classTimeName: "5",
order: 1
}
];
options.list = list;
const mock = mockUtil.buildMock(options);
export default mock;

View File

@@ -1,26 +0,0 @@
<template>
<fs-page>
<fs-crud ref="crudRef" v-bind="crudBinding" />
<advanced-in-drawer-class-time ref="drawerClassTimeRef" />
</fs-page>
</template>
<script lang="ts" setup>
import { defineComponent, onMounted, ref } from "vue";
import { useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud";
import AdvancedInDrawerClassTime from "./drawer-class-time/index.vue";
//保留子组件的ref引用
const drawerClassTimeRef = ref();
//通过context传递到crud.tsx中
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context: { drawerClassTimeRef } });
defineOptions({
name: "AdvancedInDrawer"
});
// 页面打开后获取列表数据
onMounted(() => {
crudExpose.doRefresh();
});
</script>

View File

@@ -1,25 +0,0 @@
// @ts-ignore
import mockUtil from "/src/mock/base";
const options: any = {
name: "AdvancedInDrawer",
idGenerator: 0
};
const list = [
{
textbookCategory: "初中英语",
textbookVersion: "初中人教版",
textbookName: "初一上学期",
totalWords: 200,
classTimeNumber: 40
},
{
textbookCategory: "初中英语",
textbookVersion: "初中人教版",
textbookName: "初一上学期",
totalWords: 200,
classTimeNumber: 40
}
];
options.list = list;
const mock = mockUtil.buildMock(options);
export default mock;

View File

@@ -1,42 +0,0 @@
import { requestForMock } from "/src/api/service";
const request = requestForMock;
const apiPrefix = "/mock/FormLinkage";
export function GetList(query: any) {
return request({
url: apiPrefix + "/page",
method: "get",
data: query
});
}
export function AddObj(obj: any) {
return request({
url: apiPrefix + "/add",
method: "post",
data: obj
});
}
export function UpdateObj(obj: any) {
return request({
url: apiPrefix + "/update",
method: "post",
data: obj
});
}
export function DelObj(id: any) {
return request({
url: apiPrefix + "/delete",
method: "post",
params: { id }
});
}
export function GetObj(id: any) {
return request({
url: apiPrefix + "/get",
method: "get",
params: { id }
});
}

View File

@@ -1,126 +0,0 @@
import * as api from "./api";
import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, ScopeContext, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
export default function ({ crudExpose }: CreateCrudOptionsProps): CreateCrudOptionsRet {
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
return await api.GetList(query);
};
const editRequest = async ({ form, row }: EditReq) => {
if (form.id == null) {
form.id = row.id;
}
return await api.UpdateObj(form);
};
const delRequest = async ({ row }: DelReq) => {
return await api.DelObj(row.id);
};
const addRequest = async ({ form }: AddReq) => {
return await api.AddObj(form);
};
return {
crudOptions: {
request: {
pageRequest,
addRequest,
editRequest,
delRequest
},
rowHandle: {
align: "center"
},
columns: {
id: {
title: "ID",
type: "number",
column: {
width: 50
},
form: {
show: false
}
},
province: {
title: "省",
type: "dict-select",
search: {
show: true,
valueChange({ form, value, getComponentRef }: any) {
form.city = undefined; // 将“city”的值置空
form.county = undefined; // 将“county”的值置空
if (value) {
getComponentRef("city").reloadDict(); // 执行city的select组件的reloadDict()方法触发“city”重新加载字典
}
}
},
dict: dict({
url: "/mock/linkage/province",
value: "id",
cache: true
}),
form: {
valueChange({ form, value, getComponentRef }) {
form.city = ""; // 将“city”的值置空
form.county = ""; // 将“county”的值置空
if (value) {
getComponentRef("city").reloadDict(); // 执行city的select组件的reloadDict()方法触发“city”重新加载字典
}
}
}
},
city: {
title: "市",
type: "dict-select",
search: {
show: true
},
dict: dict({
cache: true,
prototype: true,
// url() 改成构建url返回一个url
url({ form }: any) {
if (form && form.province != null) {
// 本数据字典的url是通过前一个select的选项决定的
return `/mock/linkage/city?province=${form.province}`;
}
return undefined; // 返回undefined 将不加载字典
},
value: "id"
}),
form: {
// 注释同上
valueChange({ value, form, getComponentRef }: ScopeContext) {
if (value) {
form.county = ""; // 将county的value置空
const countySelect = getComponentRef("county");
if (form && form.province && form.city) {
countySelect.reloadDict(); // 重新加载字典项
} else {
countySelect.clearDict(); // 清空选项
}
}
}
}
},
county: {
title: "区",
type: "dict-select",
search: {
show: true
},
dict: dict({
value: "id",
cache: true,
prototype: true,
url({ form }: any) {
if (form && form.province != null && form.city != null) {
return `/mock/linkage/county?province=${form.province} &city=${form.city}`;
}
return undefined;
}
})
}
}
}
};
}

View File

@@ -1,27 +0,0 @@
<template>
<fs-crud ref="crudRef" v-bind="crudBinding" />
</template>
<script lang="ts">
import { defineComponent, onMounted } from "vue";
import { useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud.js";
export default defineComponent({
name: "FormLinkage",
setup() {
const customValue: any = {}; //自定义变量传给createCrudOptions的额外参数可以任意命名任意多个
const { crudBinding, crudRef, crudExpose, context } = useFs({ createCrudOptions, context: customValue });
// 页面打开后获取列表数据
onMounted(() => {
crudExpose.doRefresh();
});
return {
crudBinding,
crudRef
};
}
});
</script>

View File

@@ -1,151 +0,0 @@
// @ts-ignore
import mockUtil from "/src/mock/base";
import _ from "lodash-es";
const options: any = {
name: "FormLinkage",
idGenerator: 0
};
const list = [
{
province: 10000,
city: 100003,
county: 100004
},
{
province: 10010,
city: 100113,
county: 100115
}
];
const tree = [
{
id: 10000,
label: "北京市",
children: [
{
id: 100003,
label: "北京市辖区",
children: [
{ id: 100004, label: "东城区" },
{ id: 100005, label: "西城区" }
]
},
{
id: 100103,
label: "北京郊区",
children: [
{ id: 100104, label: "东郊" },
{ id: 100105, label: "西郊" }
]
}
]
},
{
id: 10010,
label: "天津市",
children: [
{
id: 100013,
label: "天津市辖区",
children: [
{ id: 100014, label: "天津湾" },
{ id: 100015, label: "渤海湾" }
]
},
{
id: 100113,
label: "天津市郊区",
children: [
{ id: 100114, label: "天津湾郊区" },
{ id: 100115, label: "渤海湾郊区" }
]
}
]
}
];
options.list = list;
options.copyTimes = 100;
const mock = mockUtil.buildMock(options);
function omitChildren(originalList: any) {
const list: any = [];
originalList.forEach((item: any) => {
list.push(_.omit(item, "children"));
});
return list;
}
mock.push({
path: "/mock/linkage/province",
method: "get",
handle() {
const list = omitChildren(tree);
return {
code: 0,
msg: "success",
data: list
};
}
});
mock.push({
path: "/mock/linkage/city",
method: "get",
handle(req: any) {
const province = parseInt(req.params.province);
const a = tree.filter((item) => {
return item.id === province;
});
if (a == null || a.length === 0) {
return {
code: 0,
msg: "success",
data: []
};
}
const list = omitChildren(a[0].children);
return {
code: 0,
msg: "success",
data: list
};
}
});
mock.push({
path: "/mock/linkage/county",
method: "get",
handle(req: any) {
const province = parseInt(req.params.province);
const a = tree.filter((item) => {
return item.id === province;
});
if (a == null || a.length === 0) {
return {
code: 0,
msg: "success",
data: []
};
}
const city = parseInt(req.params.city);
const b = a[0].children.filter((item) => {
return item.id === city;
});
if (b == null || b.length === 0) {
return {
code: 0,
msg: "success",
data: []
};
}
const list = omitChildren(b[0].children);
return {
code: 0,
msg: "success",
data: list
};
}
});
export default mock;

View File

@@ -1,42 +0,0 @@
import { requestForMock } from "/src/api/service";
const request = requestForMock;
const apiPrefix = "/mock/AdvancedLocalPagination";
export function GetList(query: any) {
return request({
url: apiPrefix + "/page",
method: "get",
data: query
});
}
export function AddObj(obj: any) {
return request({
url: apiPrefix + "/add",
method: "post",
data: obj
});
}
export function UpdateObj(obj: any) {
return request({
url: apiPrefix + "/update",
method: "post",
data: obj
});
}
export function DelObj(id: any) {
return request({
url: apiPrefix + "/delete",
method: "post",
params: { id }
});
}
export function GetObj(id: any) {
return request({
url: apiPrefix + "/get",
method: "get",
params: { id }
});
}

View File

@@ -1,106 +0,0 @@
import * as api from "./api.js";
import _ from "lodash-es";
import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
const localDataRef = context.localDataRef;
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
const { page } = query;
//总数据
let data = localDataRef.value;
//获取请求参数
const limit = page.limit;
const offset = page.offset;
data = data.filter((item: any) => {
// 根据你的业务,编写你的本地查询逻辑
// text改成你的查询字段
if (query.status && item.status !== query.status) {
return false;
}
return true;
});
// 本地分页
const start = offset;
let end = offset + limit;
if (data.length < end) {
end = data.length;
}
const records = data.slice(start, end);
// 构造返回结果
return {
offset,
limit,
total: localDataRef.value.length,
records
};
};
const editRequest = async ({ form, row }: EditReq) => {
if (form.id == null) {
form.id = row.id;
}
await api.UpdateObj(form);
//更新本地数据
const tableData = localDataRef.value;
for (const item of tableData) {
if (item.id === form.id) {
_.merge(item, form);
}
}
};
const addRequest = async ({ form }: AddReq) => {
const { id } = await api.AddObj(form);
//本地添加
form.id = id;
localDataRef.value.unshift(form);
return form;
};
const delRequest = async ({ row }: DelReq) => {
await api.DelObj(row.id);
//本地删除那一条记录
const tableData = localDataRef.value;
let index = 0;
for (const item of tableData) {
if (item.id === row.id) {
localDataRef.value.splice(index, 1);
}
index++;
}
};
return {
output: {},
crudOptions: {
request: {
pageRequest,
addRequest,
editRequest,
delRequest
},
columns: {
id: {
title: "ID",
key: "id",
type: "number",
column: {
width: 50
},
form: {
show: false
}
},
status: {
title: "状态",
search: { show: true },
type: "dict-select",
dict: dict({
url: "/mock/dicts/OpenStatusEnum?single"
})
}
}
}
};
}

View File

@@ -1,51 +0,0 @@
<template>
<fs-page>
<template #header>
<div class="title">本地分页</div>
</template>
<fs-crud v-if="crudBinding" ref="crudRef" v-bind="crudBinding">
<template #actionbar-right>
<a-alert type="warning" class="ml-1" message="先从后台获取全部数据,然后本地分页展示" />
</template>
</fs-crud>
</fs-page>
</template>
<script lang="ts">
import { defineComponent, ref, onMounted } from "vue";
import { useCrud, useExpose, useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud";
import { GetList } from "./api";
/**
* 本示例演示如何本地分页
* 主要就是将pageRequest修改为从本地获取数据就行了
*/
export default defineComponent({
name: "AdvanceLocalPagination",
setup() {
// crud组件的ref
const crudRef = ref();
// crud 配置的ref
const crudBinding = ref();
const localDataRef = ref();
onMounted(async () => {
//先加载后台数据
const ret = await GetList({ page: { offset: 0, limit: 99999999 }, query: {}, sort: {} });
localDataRef.value = ret.records;
const { crudExpose } = useFs({ crudBinding, crudRef, createCrudOptions, context: { localDataRef } });
// 页面打开后获取列表数据
await crudExpose.doRefresh();
});
return {
crudBinding,
crudRef
};
}
});
</script>

View File

@@ -1,20 +0,0 @@
// @ts-ignore
import mockUtil from "/src/mock/base";
const options: any = {
name: "AdvancedLocalPagination",
idGenerator: 0
};
const list = [
{
status: "1"
},
{
status: "2"
},
{
status: "0"
}
];
options.list = list;
const mock = mockUtil.buildMock(options);
export default mock;

View File

@@ -1,50 +0,0 @@
import { requestForMock } from "/src/api/service";
const request = requestForMock;
const apiPrefix = "/mock/AdvancedNest";
export function GetList(query: any) {
return request({
url: apiPrefix + "/page",
method: "get",
data: query
});
}
export function AddObj(obj: any) {
return request({
url: apiPrefix + "/add",
method: "post",
data: obj
});
}
export function UpdateObj(obj: any) {
return request({
url: apiPrefix + "/update",
method: "post",
data: obj
});
}
export function DelObj(id: any) {
return request({
url: apiPrefix + "/delete",
method: "post",
params: { id }
});
}
export function GetObj(id: any) {
return request({
url: apiPrefix + "/get",
method: "get",
params: { id }
});
}
export function BatchDelete(ids: any[]) {
return request({
url: apiPrefix + "/batchDelete",
method: "post",
data: { ids }
});
}

View File

@@ -1,50 +0,0 @@
import { requestForMock } from "/src/api/service";
const request = requestForMock;
const apiPrefix = "/mock/AdvancedAside";
export function GetList(query: any) {
return request({
url: apiPrefix + "/page",
method: "get",
data: query
});
}
export function AddObj(obj: any) {
return request({
url: apiPrefix + "/add",
method: "post",
data: obj
});
}
export function UpdateObj(obj: any) {
return request({
url: apiPrefix + "/update",
method: "post",
data: obj
});
}
export function DelObj(id: any) {
return request({
url: apiPrefix + "/delete",
method: "post",
params: { id }
});
}
export function GetObj(id: any) {
return request({
url: apiPrefix + "/get",
method: "get",
params: { id }
});
}
export function BatchDelete(ids: any[]) {
return request({
url: apiPrefix + "/batchDelete",
method: "post",
data: { ids }
});
}

View File

@@ -1,63 +0,0 @@
import * as api from "./api";
import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
export default function ({ crudExpose }: CreateCrudOptionsProps): CreateCrudOptionsRet {
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
return await api.GetList(query);
};
const editRequest = async ({ form, row }: EditReq) => {
if (form.id == null) {
form.id = row.id;
}
return await api.UpdateObj(form);
};
const delRequest = async ({ row }: DelReq) => {
return await api.DelObj(row.id);
};
const addRequest = async ({ form }: AddReq) => {
return await api.AddObj(form);
};
return {
crudOptions: {
pagination: {
showSizeChanger: false, // antdv
showQuickJumper: false // antdv
},
request: {
pageRequest: api.GetList,
addRequest,
editRequest,
delRequest
},
toolbar: {
compact: false
},
rowHandle: {
width: "230px"
},
table: {},
columns: {
gradeId: {
title: "年级Id",
search: { show: true },
type: "number",
column: {
width: 80,
align: "center",
sortable: true
}
},
class: {
title: "班级",
search: { show: false },
type: "text",
column: {
sortable: true
}
}
}
}
};
}

View File

@@ -1,32 +0,0 @@
<template>
<fs-crud ref="crudRef" v-bind="crudBinding">
<template #actionbar-right>
<a-alert type="warning" class="ml-1" message="左侧表格点击行可以触发这里的查询" />
</template>
</fs-crud>
</template>
<script lang="ts">
import { defineComponent, onMounted } from "vue";
import createCrudOptions from "./crud.js";
import { useFs } from "@fast-crud/fast-crud";
export default defineComponent({
name: "AsideTable",
setup() {
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions });
// 页面打开后获取列表数据
onMounted(() => {
crudExpose.doRefresh();
});
return {
crudBinding,
crudRef,
setSearchFormData: crudExpose.setSearchFormData,
doRefresh: crudExpose.doRefresh
};
}
});
</script>

View File

@@ -1,27 +0,0 @@
// @ts-ignore
import mockUtil from "/src/mock/base";
const options: any = {
name: "AdvancedAside",
idGenerator: 0
};
const list = [
{
class: "一班",
gradeId: 1
},
{
class: "二班",
gradeId: 1
},
{
class: "三班",
gradeId: 2
},
{
class: "四班",
gradeId: 2
}
];
options.list = list;
const mock = mockUtil.buildMock(options);
export default mock;

View File

@@ -1,110 +0,0 @@
import * as api from "./api";
import { ref, shallowRef } from "vue";
import SubTable from "./sub-table/index.vue";
import { AddReq, compute, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
export default function ({ crudExpose, context: { asideTableRef } }: CreateCrudOptionsProps): CreateCrudOptionsRet {
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
return await api.GetList(query);
};
const editRequest = async ({ form, row }: EditReq) => {
if (form.id == null) {
form.id = row.id;
}
return await api.UpdateObj(form);
};
const delRequest = async ({ row }: DelReq) => {
return await api.DelObj(row.id);
};
const addRequest = async ({ form }: AddReq) => {
return await api.AddObj(form);
};
const currentRow = ref();
const onCurrentRowChange = (id: number) => {
currentRow.value = id;
asideTableRef.value.crudBinding.search.initialForm = { gradeId: id };
asideTableRef.value.setSearchFormData({ form: { gradeId: id } });
asideTableRef.value.doRefresh();
};
return {
crudOptions: {
table: {
customRow(record: any, index: number) {
const clazz = record.id === currentRow.value ? "fs-current-row" : "";
return {
onClick() {
onCurrentRowChange(record.id);
},
class: clazz
};
}
},
pagination: {
showSizeChanger: false, // antdv
showQuickJumper: false // antdv
},
form: {
wrapper: {
is: "a-drawer"
}
},
request: {
pageRequest: api.GetList,
addRequest,
editRequest,
delRequest
},
rowHandle: {
width: "240px"
},
toolbar: {
compact: false
},
columns: {
id: {
title: "ID",
key: "id",
type: "number",
column: {
width: 50
},
form: {
show: false
}
},
grade: {
title: "年级",
search: { show: true },
type: "text",
column: {
sortable: true
}
},
nestId: {
title: "嵌套表格",
//复合字段类型
type: ["number", "colspan"],
form: {
// 嵌套表格字段
rules: [{ required: true, message: "请选择用户" }],
component: {
//局部引用子表格要用shallowRef包裹
name: shallowRef(SubTable),
vModel: "modelValue",
gradeId: compute(({ form }) => {
return form.id;
})
}
// antdv 的跨列配置,需要配置如下三个, 可以通过colspan简化
// col: { span: 24 },
// labelCol: { span: 2 },
// wrapperCol: { span: 21 }
}
}
}
}
};
}

View File

@@ -1,49 +0,0 @@
<template>
<a-row class="demo-nest" :gutter="0">
<a-col :span="12">
<fs-crud ref="crudRef" v-bind="crudBinding">
<template #actionbar-right>
<a-alert type="warning" class="ml-1" message="<--对话框内嵌套子表格" />
</template>
</fs-crud>
</a-col>
<a-col :span="12">
<aside-table ref="asideTableRef" />
</a-col>
</a-row>
</template>
<script lang="ts">
import { defineComponent, onMounted, ref } from "vue";
import createCrudOptions from "./crud.js";
import AsideTable from "./aside-table/index.vue";
import { useFs } from "@fast-crud/fast-crud";
export default defineComponent({
name: "FeatureNest",
// eslint-disable-next-line vue/no-unused-components
components: { AsideTable },
setup() {
const asideTableRef = ref();
const { crudBinding, crudRef, crudExpose, context } = useFs({ createCrudOptions, context: { asideTableRef } });
// 页面打开后获取列表数据
onMounted(() => {
crudExpose.doRefresh();
});
return {
crudBinding,
crudRef,
asideTableRef
};
}
});
</script>
<style lang="less">
.demo-nest {
height: 100%;
width: 100%;
}
</style>

View File

@@ -1,23 +0,0 @@
// @ts-ignore
import mockUtil from "/src/mock/base";
const options: any = {
name: "AdvancedNest",
idGenerator: 0
};
const list = [
{
grade: "一年级",
nestId: 1
},
{
grade: "二年级",
nestId: 2
},
{
grade: "三年级",
nestId: 3
}
];
options.list = list;
const mock = mockUtil.buildMock(options);
export default mock;

View File

@@ -1,50 +0,0 @@
import { requestForMock } from "/src/api/service";
const request = requestForMock;
const apiPrefix = "/mock/AdvancedSubTable";
export function GetList(query: any) {
return request({
url: apiPrefix + "/page",
method: "get",
data: query
});
}
export function AddObj(obj: any) {
return request({
url: apiPrefix + "/add",
method: "post",
data: obj
});
}
export function UpdateObj(obj: any) {
return request({
url: apiPrefix + "/update",
method: "post",
data: obj
});
}
export function DelObj(id: any) {
return request({
url: apiPrefix + "/delete",
method: "post",
params: { id }
});
}
export function GetObj(id: any) {
return request({
url: apiPrefix + "/get",
method: "get",
params: { id }
});
}
export function BatchDelete(ids: any[]) {
return request({
url: apiPrefix + "/batchDelete",
method: "post",
data: { ids }
});
}

View File

@@ -1,70 +0,0 @@
import * as api from "./api";
import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
export default function ({ crudExpose, context: { props, ctx } }: CreateCrudOptionsProps): CreateCrudOptionsRet {
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
return await api.GetList(query);
};
const editRequest = async ({ form, row }: EditReq) => {
if (form.id == null) {
form.id = row.id;
}
return await api.UpdateObj(form);
};
const delRequest = async ({ row }: DelReq) => {
return await api.DelObj(row.id);
};
const addRequest = async ({ form }: AddReq) => {
return await api.AddObj(form);
};
return {
crudOptions: {
table: {
customRow(record: any, index: number) {
const clazz = record.id === props.modelValue ? "fs-current-row" : "";
return {
onClick() {
ctx.emit("update:modelValue", record.id);
},
class: clazz
};
}
},
request: {
pageRequest: api.GetList,
addRequest,
editRequest,
delRequest
},
search: { show: false },
form: {
wrapper: {
is: "a-drawer"
}
},
columns: {
id: {
title: "ID",
key: "id",
type: "number",
column: {
width: 50
},
form: {
show: false
}
},
name: {
title: "用户姓名",
search: { show: true },
type: "text",
column: {
sortable: true
}
}
}
}
};
}

View File

@@ -1,50 +0,0 @@
<template>
<div>
<div>年级id{{ gradeId }},当前选中值{{ modelValue }}</div>
<div style="height: 400px">
<fs-crud ref="crudRef" v-bind="crudBinding" />
</div>
</div>
</template>
<script lang="ts">
import { defineComponent, onMounted, watch } from "vue";
import createCrudOptions from "./crud";
import {useFs, utils} from "@fast-crud/fast-crud";
export default defineComponent({
name: "SubTable",
props: {
modelValue: {},
gradeId: {} //年级id接收其他参数
},
emits: ["update:modelValue"],
setup(props, ctx) {
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context: { props, ctx } });
// 页面打开后获取列表数据
onMounted(() => {
crudExpose.doRefresh();
});
//你的业务代码
watch(
() => {
return props.modelValue;
},
(value) => {
utils.logger.info("modelValue changed", value);
}
);
return {
crudBinding,
crudRef
};
}
});
</script>
<style lang="less" scoped>
/deep/.fs-crud-container.compact .el-table--border {
border-left: 1px solid #eee;
}
</style>

View File

@@ -1,20 +0,0 @@
// @ts-ignore
import mockUtil from "/src/mock/base";
const options: any = {
name: "AdvancedSubTable",
idGenerator: 0
};
const list = [
{
name: "张三"
},
{
name: "李四"
},
{
name: "王五"
}
];
options.list = list;
const mock = mockUtil.buildMock(options);
export default mock;

View File

@@ -1,42 +0,0 @@
import { requestForMock } from "/src/api/service";
const request = requestForMock;
const apiPrefix = "/mock/BasisColumnMergePlugin";
export function GetList(query: any) {
return request({
url: apiPrefix + "/page",
method: "get",
data: query
});
}
export function AddObj(obj: any) {
return request({
url: apiPrefix + "/add",
method: "post",
data: obj
});
}
export function UpdateObj(obj: any) {
return request({
url: apiPrefix + "/update",
method: "post",
data: obj
});
}
export function DelObj(id: any) {
return request({
url: apiPrefix + "/delete",
method: "post",
params: { id }
});
}
export function GetObj(id: any) {
return request({
url: apiPrefix + "/get",
method: "get",
params: { id }
});
}

View File

@@ -1,70 +0,0 @@
import * as api from "./api";
import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
export default function ({ crudExpose }: CreateCrudOptionsProps): CreateCrudOptionsRet {
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
return await api.GetList(query);
};
const editRequest = async ({ form, row }: EditReq) => {
if (form.id == null) {
form.id = row.id;
}
return await api.UpdateObj(form);
};
const delRequest = async ({ row }: DelReq) => {
return await api.DelObj(row.id);
};
const addRequest = async ({ form }: AddReq) => {
return await api.AddObj(form);
};
return {
crudOptions: {
settings: {
viewFormUseCellComponent: true
},
request: {
pageRequest,
addRequest,
editRequest,
delRequest
},
columns: {
id: {
title: "ID",
key: "id",
type: "number",
column: {
width: 50
},
form: {
show: false
}
},
text: {
title: "text",
type: "text"
},
readonly: {
title: "只读字段",
type: "text",
readonly: true
},
useCell: {
title: "查看使用cell组件",
type: "dict-select",
readonly: true,
dict: dict({
url: "/mock/dicts/OpenStatusEnum"
}),
viewForm: {
component: {
vModel: "modelValue"
}
}
}
}
}
};
}

View File

@@ -1,35 +0,0 @@
<template>
<fs-page>
<template #header>
<div class="title">可以实现类似dict的公共属性</div>
<div class="more"><a target="_blank" href="http://fast-crud.docmirror.cn/guide/advance/column-type.html#修改官方字段类型配置"> 字段合并插件帮助文档</a></div>
</template>
<fs-crud ref="crudRef" v-bind="crudBinding">
<template #actionbar-right>
<span class="fs-desc">此示例实现只需配置readonly: true即可关闭添加和编辑时该字段的显示更多说明请点击右上角帮助</span>
</template>
</fs-crud>
</fs-page>
</template>
<script lang="ts">
import { defineComponent, ref, onMounted } from "vue";
import createCrudOptions from "./crud";
import { useFs, UseFsProps } from "@fast-crud/fast-crud";
export default defineComponent({
name: "BasisColumnMergePlugin",
setup() {
const context: any = {}; //自定义变量传给createCrudOptions的额外参数可以任意命名任意多个
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context });
// 页面打开后获取列表数据
onMounted(() => {
crudExpose.doRefresh();
});
return {
crudBinding,
crudRef
};
}
});
</script>

View File

@@ -1,26 +0,0 @@
// @ts-ignore
import mockUtil from "/src/mock/base";
const options: any = {
name: "BasisColumnMergePlugin",
idGenerator: 0
};
const list = [
{
text: "点击右边查看按钮看效果",
readonly: "我是只读",
useCell: "1"
},
{
text: "点击编辑按钮查看效果",
readonly: "我是只读",
useCell: "2"
},
{
text: "正常字段",
readonly: "我是只读",
useCell: "0"
}
];
options.list = list;
const mock = mockUtil.buildMock(options);
export default mock;

View File

@@ -1,50 +0,0 @@
import { requestForMock } from "/src/api/service";
const request = requestForMock;
const apiPrefix = "/mock/BasisColumnsSet";
export function GetList(query: any) {
return request({
url: apiPrefix + "/page",
method: "get",
data: query
});
}
export function AddObj(obj: any) {
return request({
url: apiPrefix + "/add",
method: "post",
data: obj
});
}
export function UpdateObj(obj: any) {
return request({
url: apiPrefix + "/update",
method: "post",
data: obj
});
}
export function DelObj(id: any) {
return request({
url: apiPrefix + "/delete",
method: "post",
params: { id }
});
}
export function GetObj(id: any) {
return request({
url: apiPrefix + "/get",
method: "get",
params: { id }
});
}
export function BatchDelete(ids: any) {
return request({
url: apiPrefix + "/batchDelete",
method: "post",
data: { ids }
});
}

View File

@@ -1,109 +0,0 @@
import * as api from "./api.js";
import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
import { message } from "ant-design-vue";
import { computed } from "vue";
export default function ({ crudExpose }: CreateCrudOptionsProps): CreateCrudOptionsRet {
const { crudBinding } = crudExpose;
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
return await api.GetList(query);
};
const editRequest = async ({ form, row }: EditReq) => {
if (form.id == null) {
form.id = row.id;
}
return await api.UpdateObj(form);
};
const delRequest = async ({ row }: DelReq) => {
return await api.DelObj(row.id);
};
const addRequest = async ({ form }: AddReq) => {
return await api.AddObj(form);
};
return {
crudOptions: {
request: {
pageRequest,
addRequest,
editRequest,
delRequest
},
toolbar: {
columnsFilter: {
mode: "default",
container: {
width: "500px"
}
}
},
actionbar: {
buttons: {
toggleMode: {
text: "切换简单模式",
click() {
crudBinding.value.toolbar.columnsFilter.mode = crudBinding.value.toolbar.columnsFilter.mode === "simple" ? "default" : "simple";
message.info("当前列设置组件的模式为:" + crudBinding.value.toolbar.columnsFilter.mode);
}
},
toggleColumnSetShow: {
text: "切换列设置项显隐",
click() {
crudBinding.value.toolbar.columnsFilter.originalColumns.hidden.columnSetShow = !crudBinding.value.toolbar.columnsFilter.originalColumns.hidden.columnSetShow;
message.info("切换第4列的列设置显隐");
}
},
toggleColumnSetDisabled: {
text: "切换列设置项禁用",
click() {
crudBinding.value.toolbar.columnsFilter.originalColumns.disabled.columnSetDisabled = !crudBinding.value.toolbar.columnsFilter.originalColumns.disabled.columnSetDisabled;
message.info("切换第3列的列设置禁用启用");
}
},
desc: {
text: "点击左侧按钮后,再点最右侧的列设置按钮查看效果"
}
}
},
columns: {
id: {
title: "ID",
key: "id",
type: "number",
column: {
width: 50
},
form: {
show: false
}
},
radio: {
title: "状态",
search: { show: true },
type: "dict-radio",
dict: dict({
url: "/mock/dicts/OpenStatusEnum?single"
}),
column: {
show: computed(() => {
return true;
})
}
},
disabled: {
title: "列设置禁用",
type: "text",
column: {
columnSetDisabled: true
}
},
hidden: {
title: "列设置隐藏",
type: "text",
column: {
columnSetShow: false
}
}
}
}
};
}

View File

@@ -1,48 +0,0 @@
<template>
<fs-page>
<template #header>
<div class="title">
列设置
<span class="sub">列设置可以禁用或者隐藏某字段勾选 -------> 点击右侧最后一个按钮查看效果</span>
</div>
<div class="more">
<a target="_blank" href="http://fast-crud.docmirror.cn/api/crud-options/toolbar.html#columnsfilter-mode">文档</a>
</div>
</template>
<fs-crud ref="crudRef" v-bind="crudBinding"> </fs-crud>
</fs-page>
</template>
<script lang="ts">
import { defineComponent, onMounted } from "vue";
import createCrudOptions from "./crud";
import { useFs } from "@fast-crud/fast-crud";
import { message } from "ant-design-vue";
export default defineComponent({
name: "BasisColumnsSet",
setup() {
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions });
// 页面打开后获取列表数据
onMounted(() => {
crudExpose.doRefresh();
});
function columnsSetToggleMode() {
crudBinding.value.toolbar.columnsFilter.mode = crudBinding.value.toolbar.columnsFilter.mode === "simple" ? "default" : "simple";
message.info("点击列设置按钮查看效果,当前列设置组件的模式为:" + crudBinding.value.toolbar.columnsFilter.mode);
}
function columnsSetShowToggle() {
crudBinding.value.table.columns.disabled.columnSetShow = !crudBinding.value.table.columns.disabled.columnSetShow;
}
return {
crudBinding,
crudRef,
columnsSetToggleMode,
columnsSetShowToggle
};
}
});
</script>

View File

@@ -1,20 +0,0 @@
// @ts-ignore
import mockUtil from "/src/mock/base";
const options: any = {
name: "BasisColumnsSet",
idGenerator: 0
};
const list = [
{
radio: "1"
},
{
radio: "2"
},
{
radio: "0"
}
];
options.list = list;
const mock = mockUtil.buildMock(options);
export default mock;

View File

@@ -1,42 +0,0 @@
import { requestForMock } from "/src/api/service";
const request = requestForMock;
const apiPrefix = "/mock/FormComputeMore";
export function GetList(query: any) {
return request({
url: apiPrefix + "/page",
method: "get",
data: query
});
}
export function AddObj(obj: any) {
return request({
url: apiPrefix + "/add",
method: "post",
data: obj
});
}
export function UpdateObj(obj: any) {
return request({
url: apiPrefix + "/update",
method: "post",
data: obj
});
}
export function DelObj(id: any) {
return request({
url: apiPrefix + "/delete",
method: "post",
params: { id }
});
}
export function GetObj(id: any) {
return request({
url: apiPrefix + "/get",
method: "get",
params: { id }
});
}

View File

@@ -1,104 +0,0 @@
import * as api from "./api";
import { AddReq, compute, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
import { computed, ref, shallowRef } from "vue";
import ShallowComponent from "/@/views/crud/basis/compute-more/shallow-component.vue";
export default function ({ crudExpose }: CreateCrudOptionsProps): CreateCrudOptionsRet {
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
return await api.GetList(query);
};
const editRequest = async ({ form, row }: EditReq) => {
if (form.id == null) {
form.id = row.id;
}
return await api.UpdateObj(form);
};
const delRequest = async ({ row }: DelReq) => {
return await api.DelObj(row.id);
};
const addRequest = async ({ form }: AddReq) => {
return await api.AddObj(form);
};
//普通的ref引用可以动态切换配置
const defValueRef = ref("我是动态的默认值");
return {
output: {
defValueRef
},
crudOptions: {
request: {
pageRequest,
addRequest,
editRequest,
delRequest
},
table: {
scroll: {
x: 1500
}
},
form: {
labelCol: { span: 8 },
wrapperCol: { span: 14 }
},
rowHandle: {
fixed: "right",
align: "center"
},
columns: {
id: {
title: "ID",
key: "id",
type: "number",
column: {
width: 50
},
form: {
show: false
}
},
defValue: {
title: "默认值",
type: "text",
search: { show: true, value: null },
form: {
// form.value不支持asyncCompute/Compute, 因为上下文动态计算要先有上下文上下文需要先有form数据
value: defValueRef
}
},
switch: {
title: "切换动态组件",
type: "dict-radio",
dict: dict({
data: [
{ value: "radio", label: "radio" },
{ value: "select", label: "select" },
{ value: "shallow", label: "shallowComponent" }
]
})
},
componentName: {
title: "动态组件",
type: "dict-select",
search: { show: true, value: null },
dict: dict({
data: [
{ value: "1", label: "开启" },
{ value: "2", label: "关闭" }
]
}),
form: {
component: {
value: "2",
name: compute(({ form }) => {
return form.switch === "select" ? "fs-dict-select" : form.switch === "radio" ? "fs-dict-radio" : ShallowComponent;
})
}
}
}
}
}
};
}

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