合同相对人功能开发

This commit is contained in:
z9130 2024-09-13 12:59:28 +08:00
parent 8aeccb9fbf
commit 4c326f9b58
32 changed files with 2257 additions and 2851 deletions

View File

@ -1,5 +0,0 @@
node_modules
.git
.gitignore
*.md
dist

View File

@ -1,31 +0,0 @@
FROM node:20-slim AS builder
# --max-old-space-size
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
ENV NODE_OPTIONS=--max-old-space-size=8192
ENV TZ=Asia/Shanghai
RUN corepack enable
WORKDIR /app
# copy package.json and pnpm-lock.yaml to workspace
COPY . /app
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile
RUN pnpm run build
RUN echo "Builder Success 🎉"
FROM nginx:stable-alpine as production
RUN echo "types { application/javascript js mjs; }" > /etc/nginx/conf.d/mjs.conf
COPY --from=builder /app/playground/dist /usr/share/nginx/html
COPY ./nginx.conf /etc/nginx/nginx.conf
EXPOSE 8080
# start nginx
CMD ["nginx", "-g", "daemon off;"]

View File

@ -1,9 +0,0 @@
MIT License
Copyright (c) 2024-present, Vben
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,149 +0,0 @@
<div align="center"> <a href="https://github.com/anncwb/vue-vben-admin"> <img alt="VbenAdmin Logo" width="215" src="https://unpkg.com/@vbenjs/static-source@0.1.6/source/logo-v1.webp"> </a> <br> <br>
[![license](https://img.shields.io/github/license/anncwb/vue-vben-admin.svg)](LICENSE)
<h1>Vue Vben Admin</h1>
</div>
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=vbenjs_vue-vben-admin&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=vbenjs_vue-vben-admin) ![codeql](https://github.com/vbenjs/vue-vben-admin/actions/workflows/codeql.yml/badge.svg) ![build](https://github.com/vbenjs/vue-vben-admin/actions/workflows/build.yml/badge.svg) ![ci](https://github.com/vbenjs/vue-vben-admin/actions/workflows/ci.yml/badge.svg) ![deploy](https://github.com/vbenjs/vue-vben-admin/actions/workflows/deploy.yml/badge.svg)
**日本語** | [English](./README.md) | [中文](./README.zh-CN.md)
## 紹介
Vue Vben Adminは、最新の`vue3`、`vite`、`TypeScript`などの主流技術を使用して開発された、無料でオープンソースの中・後端テンプレートです。すぐに使える中・後端のフロントエンドソリューションとして、学習の参考にもなります。
## アップグレード通知
これは最新バージョン5.0であり、以前のバージョンとは互換性がありません。新しいプロジェクトを開始する場合は、最新バージョンを使用することをお勧めします。古いバージョンを表示したい場合は、[v2ブランチ](https://github.com/vbenjs/vue-vben-admin/tree/v2)を使用してください。
## 特徴
- **最新技術スタック**: Vue 3やViteなどの最先端フロントエンド技術で開発
- **TypeScript**: アプリケーション規模のJavaScriptのための言語
- **テーマ**: 複数のテーマカラーが利用可能で、カスタマイズオプションも豊富
- **国際化**: 完全な内蔵国際化サポート
- **権限管理**: 動的ルートベースの権限生成ソリューションを内蔵
## プレビュー
- [Vben Admin](https://vben.pro/) - フルバージョンの中国語サイト
テストアカウント: vben/123456
<p align="center">
<img alt="VbenAdmin Logo" width="100%" src="https://anncwb.github.io/anncwb/images/preview1.png">
<img alt="VbenAdmin Logo" width="100%" src="https://anncwb.github.io/anncwb/images/preview2.png">
<img alt="VbenAdmin Logo" width="100%" src="https://anncwb.github.io/anncwb/images/preview3.png">
</p>
### Gitpodを使用
GitpodGitHub用の無料オンライン開発環境でプロジェクトを開き、すぐにコーディングを開始します。
[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/vbenjs/vue-vben-admin)
## ドキュメント
[ドキュメント](https://doc.vben.pro/)
## インストールと使用
- プロジェクトコードを取得
```bash
git clone https://github.com/vbenjs/vue-vben-admin.git
```
- 依存関係のインストール
```bash
cd vue-vben-admin
corepack enable
pnpm install
```
- 実行
```bash
pnpm dev
```
- ビルド
```bash
pnpm build
```
## 変更ログ
[CHANGELOG](https://github.com/vbenjs/vue-vben-admin/releases)
## 貢献方法
ご参加をお待ちしております![Issueを提出](https://github.com/anncwb/vue-vben-admin/issues/new/choose)するか、Pull Requestを送信してください。
**Pull Request:**
1. コードをフォーク!
2. 自分のブランチを作成: `git checkout -b feat/xxxx`
3. 変更をコミット: `git commit -am 'feat(function): add xxxxx'`
4. ブランチをプッシュ: `git push origin feat/xxxx`
5. `pull request`を送信
## Git貢献提出規則
- 参考 [vue](https://github.com/vuejs/vue/blob/dev/.github/COMMIT_CONVENTION.md) 規則 ([Angular](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-angular))
- `feat` 新機能の追加
- `fix` 問題/バグの修正
- `style` コードスタイルに関連し、実行結果に影響しない
- `perf` 最適化/パフォーマンス向上
- `refactor` リファクタリング
- `revert` 変更の取り消し
- `test` テスト関連
- `docs` ドキュメント/注釈
- `chore` 依存関係の更新/スキャフォールディング設定の変更など
- `ci` 継続的インテグレーション
- `types` 型定義ファイルの変更
- `wip` 開発中
## ブラウザサポート
ローカル開発には`Chrome 80+`ブラウザを推奨します
モダンブラウザをサポートし、IEはサポートしません
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt=" Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>IE | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt=" Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari |
| :-: | :-: | :-: | :-: | :-: |
| サポートしない | 最新2バージョン | 最新2バージョン | 最新2バージョン | 最新2バージョン |
## メンテナー
[@Vben](https://github.com/anncwb)
## 寄付
このプロジェクトが役に立つと思われた場合、作者にコーヒーを一杯おごってサポートを示すことができます!
![donate](https://unpkg.com/@vbenjs/static-source@0.1.6/source/sponsor.png)
<a style="display: block;width: 100px;height: 50px;line-height: 50px; color: #fff;text-align: center; background: #408aed;border-radius: 4px;" href="https://www.paypal.com/paypalme/cvvben">Paypal Me</a>
## 貢献者
<a href="https://github.com/vbenjs/vue-vben-admin/graphs/contributors">
<img alt="Contributors"
src="https://opencollective.com/vbenjs/contributors.svg?button=false" />
</a>
## Discord
- [Github Discussions](https://github.com/anncwb/vue-vben-admin/discussions)
## ライセンス
[MIT © Vben-2020](./LICENSE)

148
README.md
View File

@ -1,148 +0,0 @@
<div align="center"> <a href="https://github.com/anncwb/vue-vben-admin"> <img alt="VbenAdmin Logo" width="215" src="https://unpkg.com/@vbenjs/static-source@0.1.6/source/logo-v1.webp"> </a> <br> <br>
[![license](https://img.shields.io/github/license/anncwb/vue-vben-admin.svg)](LICENSE)
<h1>Vue Vben Admin</h1>
</div>
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=vbenjs_vue-vben-admin&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=vbenjs_vue-vben-admin) ![codeql](https://github.com/vbenjs/vue-vben-admin/actions/workflows/codeql.yml/badge.svg) ![build](https://github.com/vbenjs/vue-vben-admin/actions/workflows/build.yml/badge.svg) ![ci](https://github.com/vbenjs/vue-vben-admin/actions/workflows/ci.yml/badge.svg) ![deploy](https://github.com/vbenjs/vue-vben-admin/actions/workflows/deploy.yml/badge.svg)
**English** | [中文](./README.zh-CN.md) | [日本語](./README.ja-JP.md)
## Introduction
Vue Vben Admin is a free and open source middle and back-end template. Using the latest `vue3`, `vite`, `TypeScript` and other mainstream technology development, the out-of-the-box middle and back-end front-end solutions can also be used for learning reference.
## Upgrade Notice
This is the latest version, 5.0, and it is not compatible with previous versions. If you are starting a new project, it is recommended to use the latest version. If you wish to view the old version, please use the [v2 branch](https://github.com/vbenjs/vue-vben-admin/tree/v2).
## Feature
- **Latest Technology Stack**: Developed with cutting-edge front-end technologies like Vue 3 and Vite
- **TypeScript**: A language for application-scale JavaScript
- **Themes**: Multiple theme colors available with customizable options
- **Internationalization**: Comprehensive built-in internationalization support
- **Permissions**: Built-in solution for dynamic route-based permission generation
## Preview
- [Vben Admin](https://vben.pro/) - Full version Chinese site
Test Account: vben/123456
<p align="center">
<img alt="VbenAdmin Logo" width="100%" src="https://anncwb.github.io/anncwb/images/preview1.png">
<img alt="VbenAdmin Logo" width="100%" src="https://anncwb.github.io/anncwb/images/preview2.png">
<img alt="VbenAdmin Logo" width="100%" src="https://anncwb.github.io/anncwb/images/preview3.png">
</p>
### Use Gitpod
Open the project in Gitpod (free online dev environment for GitHub) and start coding immediately.
[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/vbenjs/vue-vben-admin)
## Documentation
[Document](https://doc.vben.pro/)
## Install and use
- Get the project code
```bash
git clone https://github.com/vbenjs/vue-vben-admin.git
```
- Installation dependencies
```bash
cd vue-vben-admin
corepack enable
pnpm install
```
- run
```bash
pnpm dev
```
- build
```bash
pnpm build
```
## Change Log
[CHANGELOG](https://github.com/vbenjs/vue-vben-admin/releases)
## How to contribute
You are very welcome to join[Raise an issue](https://github.com/anncwb/vue-vben-admin/issues/new/choose) Or submit a Pull Request。
**Pull Request:**
1. Fork code!
2. Create your own branch: `git checkout -b feat/xxxx`
3. Submit your changes: `git commit -am 'feat(function): add xxxxx'`
4. Push your branch: `git push origin feat/xxxx`
5. submit`pull request`
## Git Contribution submission specification
- reference [vue](https://github.com/vuejs/vue/blob/dev/.github/COMMIT_CONVENTION.md) specification ([Angular](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-angular))
- `feat` Add new features
- `fix` Fix the problem/BUG
- `style` The code style is related and does not affect the running result
- `perf` Optimization/performance improvement
- `refactor` Refactor
- `revert` Undo edit
- `test` Test related
- `docs` Documentation/notes
- `chore` Dependency update/scaffolding configuration modification etc.
- `ci` Continuous integration
- `types` Type definition file changes
- `wip` In development
## Browser support
The `Chrome 80+` browser is recommended for local development
Support modern browsers, not IE
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt=" Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>IE | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt=" Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari |
| :-: | :-: | :-: | :-: | :-: |
| not support | last 2 versions | last 2 versions | last 2 versions | last 2 versions |
## Maintainer
[@Vben](https://github.com/anncwb)
## Donate
If you think this project is helpful to you, you can help the author buy a cup of coffee to show your support!
![donate](https://unpkg.com/@vbenjs/static-source@0.1.6/source/sponsor.png)
<a style="display: block;width: 100px;height: 50px;line-height: 50px; color: #fff;text-align: center; background: #408aed;border-radius: 4px;" href="https://www.paypal.com/paypalme/cvvben">Paypal Me</a>
## Contributor
<a href="https://github.com/vbenjs/vue-vben-admin/graphs/contributors">
<img alt="Contributors"
src="https://opencollective.com/vbenjs/contributors.svg?button=false" />
</a>
## Discord
- [Github Discussions](https://github.com/anncwb/vue-vben-admin/discussions)
## License
[MIT © Vben-2020](./LICENSE)

View File

@ -1,148 +0,0 @@
<div align="center"> <a href="https://github.com/anncwb/vue-vben-admin"> <img alt="VbenAdmin Logo" width="215" src="https://unpkg.com/@vbenjs/static-source@0.1.6/source/logo-v1.webp"> </a> <br> <br>
[![license](https://img.shields.io/github/license/anncwb/vue-vben-admin.svg)](LICENSE)
<h1>Vue Vben Admin</h1>
</div>
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=vbenjs_vue-vben-admin&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=vbenjs_vue-vben-admin) ![codeql](https://github.com/vbenjs/vue-vben-admin/actions/workflows/codeql.yml/badge.svg) ![build](https://github.com/vbenjs/vue-vben-admin/actions/workflows/build.yml/badge.svg) ![ci](https://github.com/vbenjs/vue-vben-admin/actions/workflows/ci.yml/badge.svg) ![deploy](https://github.com/vbenjs/vue-vben-admin/actions/workflows/deploy.yml/badge.svg)
**中文** | [English](./README.md) | [日本語](./README.ja-JP.md)
## 简介
Vue Vben Admin 是 Vue Vben Admin 的升级版本。作为一个免费开源的中后台模板,它采用了最新的 Vue 3、Vite、TypeScript 等主流技术开发,开箱即用,可用于中后台前端开发,也适合学习参考。
## 升级提示
该版本为最新版本`5.0`, 与其他版本不兼容,如果你是新项目,建议使用最新版本。如果你想查看旧版本,请使用 [v2 分支](https://github.com/vbenjs/vue-vben-admin/tree/v2)
## 特性
- **最新技术栈**:使用 Vue3/vite 等前端前沿技术开发
- **TypeScript**: 应用程序级 JavaScript 的语言
- **主题**:提供多套主题色彩,可配置自定义主题
- **国际化**:内置完善的国际化方案
- **权限** 内置完善的动态路由权限生成方案
## 预览
- [Vben Admin](https://vben.pro/) - 完整版中文站点
测试账号: vben/123456
<p align="center">
<img alt="VbenAdmin Logo" width="100%" src="https://anncwb.github.io/anncwb/images/preview1.png">
<img alt="VbenAdmin Logo" width="100%" src="https://anncwb.github.io/anncwb/images/preview2.png">
<img alt="VbenAdmin Logo" width="100%" src="https://anncwb.github.io/anncwb/images/preview3.png">
</p>
### 使用 Gitpod
在 Gitpod适用于 GitHub 的免费在线开发环境)中打开项目,并立即开始编码.
[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/vbenjs/vue-vben-admin)
## 文档
[文档地址](https://doc.vben.pro/)
## 安装使用
- 获取项目代码
```bash
git clone https://github.com/vbenjs/vue-vben-admin.git
```
- 安装依赖
```bash
cd vue-vben-admin
corepack enable
pnpm install
```
- 运行
```bash
pnpm dev
```
- 打包
```bash
pnpm build
```
## 如何贡献
非常欢迎你的加入![提一个 Issue](https://github.com/anncwb/vue-vben-admin/issues/new/choose) 或者提交一个 Pull Request。
**Pull Request:**
1. Fork 代码!
2. 创建自己的分支: `git checkout -b feature/xxxx`
3. 提交你的修改: `git commit -am 'feat(function): add xxxxx'`
4. 推送您的分支: `git push origin feature/xxxx`
5. 提交`pull request`
## Git 贡献提交规范
- 参考 [vue](https://github.com/vuejs/vue/blob/dev/.github/COMMIT_CONVENTION.md) 规范 ([Angular](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-angular))
- `feat` 增加新功能
- `fix` 修复问题/BUG
- `style` 代码风格相关无影响运行结果的
- `perf` 优化/性能提升
- `refactor` 重构
- `revert` 撤销修改
- `test` 测试相关
- `docs` 文档/注释
- `chore` 依赖更新/脚手架配置修改等
- `ci` 持续集成
- `types` 类型定义文件更改
- `wip` 开发中
## 浏览器支持
本地开发推荐使用`Chrome 80+` 浏览器
支持现代浏览器, 不支持 IE
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt=" Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>IE | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt=" Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari |
| :-: | :-: | :-: | :-: | :-: |
| not support | last 2 versions | last 2 versions | last 2 versions | last 2 versions |
## 维护者
[@Vben](https://github.com/anncwb)
## 捐赠
如果你觉得这个项目对你有帮助,你可以帮作者买一杯咖啡表示支持!
![donate](https://unpkg.com/@vbenjs/static-source@0.1.6/source/sponsor.png)
<a style="display: block;width: 100px;height: 50px;line-height: 50px; color: #fff;text-align: center; background: #408aed;border-radius: 4px;" href="https://www.paypal.com/paypalme/cvvben">Paypal Me</a>
## 更新日志
[CHANGELOG](https://github.com/vbenjs/vue-vben-admin/releases)
## Contributor
<a href="https://github.com/vbenjs/vue-vben-admin/graphs/contributors">
<img alt="Contributors"
src="https://opencollective.com/vbenjs/contributors.svg?button=false" />
</a>
## Discord
- [Github Discussions](https://github.com/anncwb/vue-vben-admin/discussions)
## License
[MIT © Vben-2020](./LICENSE)

View File

@ -171,7 +171,7 @@ VXETable.use(VXETablePluginExportXLSX, {
})
VXETable.setConfig({
zIndex: 9999,
// zIndex: 9999,
grid: {
size: 'mini',
proxyConfig: {

View File

@ -31,6 +31,9 @@ const coreRoutes: RouteRecordRaw[] = [
},
{
component: AuthPageLayout,
props: {
toolbar: false,
},
meta: {
title: 'Authentication',
},

View File

@ -84,7 +84,7 @@ const routes: RouteRecordRaw[] = [
},
children: [
{
name: 'ContractBusiness',
name: 'ContractBusinessEdit',
path: '/contract/business/edit/:id?',
beforeEnter: (e) => {
if (e.params.id && e.params.id === ':id') {
@ -129,6 +129,24 @@ const routes: RouteRecordRaw[] = [
title: '合同申报',
},
children: [
{
name: 'ContractDeclarationEdit',
path: '/contract/declaration/edit/:id?',
beforeEnter: (e) => {
if (e.params.id && e.params.id === ':id') {
e.params.id = ''
e.fullPath = '/contract/declaration/edit'
}
},
component: () => import('#/views/contract/declaration/edit/index.vue'),
meta: {
hideInMenu: true,
hideInTab: true,
icon: 'lucide:area-chart',
title: '申报填报',
activePath: '/contract/declaration/edit/:id?'
},
},
{
name: 'ContractDeclarationTodo',
path: '/contract/declaration/todo',

View File

@ -33,7 +33,7 @@ const formSchema = computed((): VbenFormSchema[] => {
{
component: 'VbenInput',
componentProps: {
class:"w-full",
class: 'w-full',
placeholder: $t('authentication.usernameTip'),
},
dependencies: {
@ -79,18 +79,23 @@ function mockLogin(username: string, password: string, isSkip: boolean = true) {
</script>
<template>
<AuthenticationLogin
:form-schema="formSchema"
:loading="authStore.loginLoading"
@submit="authStore.authLogin"
/>
<div class="w-[90%]">
<AuthenticationLogin
:form-schema="formSchema"
:loading="authStore.loginLoading"
@submit="authStore.authLogin"
/>
</div>
<div v-if="isDev">
<p class="text-center">快速登录</p>
<a-space>
<a-button @click="mockLogin('Admin.itl', 'ABC123')">超级管理员</a-button>
<a-button @click="mockLogin('zhangxs.itl', 'Rlgs!6243910')">zxs</a-button>
<a-button @click="mockLogin('zengp.itl', 'Rlgs!6243910')">zp</a-button>
<a-button @click="mockLogin('rlqym', 'Rlgs!6243910', false)">rlqym</a-button>
<a-button @click="mockLogin('rlqym', 'Rlgs!6243910', false)"
>rlqym</a-button
>
</a-space>
</div>
</template>

View File

@ -1,77 +1,92 @@
<script setup lang="ts">
import { defineComponent, ref, reactive, onMounted, nextTick } from 'vue';
import { FsCrud } from '@fast-crud/fast-crud';
import { type VxeGridProps } from 'vxe-table'
import { type VxeGridProps } from 'vxe-table';
import { Page, useVbenModal } from '@vben/common-ui';
import { useVxeTable } from '#/hooks/vxeTable';
import { MdiAdd, MdiUpdate, MdiDelete } from '@vben/icons';
import { dict } from "@fast-crud/fast-crud";
import { dict } from '@fast-crud/fast-crud';
import { getColumns } from './crud';
import Apis from '#/api'
import Apis from '#/api';
import { message, Modal } from 'ant-design-vue';
import chooseUserModal from "#/views/system/user/choose-user-modal.vue";
import chooseUserModal from '#/views/system/user/choose-user-modal.vue';
const [ChooseUserModal, chooseUserModalApi] = useVbenModal({
connectedComponent: chooseUserModal,
});
const { xGridRef, triggerProxy, gridProps } = useVxeTable({ ref: 'xGridRef' });
const { xGridRef: xGrid2Ref, triggerProxy: triggerProxy2 } = useVxeTable({ ref: 'xGrid2Ref' });
const { xGridRef: xGrid2Ref, triggerProxy: triggerProxy2 } = useVxeTable({
ref: 'xGrid2Ref',
});
let selectRow = ref({})
let selectRow = ref({});
const treeData = ref([]);
/** Hooks - 表格 */
const gridOptions = reactive(gridProps({
height: '100%',
size: 'mini',
columns: getColumns({ todoType: 'todo' }),
proxyConfig: {
autoLoad: true,
ajax: {
query: ({ page }) => {
return Apis.ccsq.get_toDoPage({ params: { pageNum: page.currentPage, pageSize: page.pageSize, ...searchParams } })
}
const gridOptions = reactive(
gridProps({
height: '100%',
size: 'mini',
columns: getColumns({ todoType: 'todo' }),
proxyConfig: {
autoLoad: true,
ajax: {
query: ({ page }) => {
return Apis.ccsq.get_toDoPage({
params: {
pageNum: page.currentPage,
pageSize: page.pageSize,
...searchParams,
},
});
},
},
},
},
pagerConfig: {
enabled: true
},
toolbarConfig: {
enabled: false
},
}));
pagerConfig: {
enabled: true,
},
toolbarConfig: {
enabled: false,
},
}),
);
/** Hooks - 表格 */
const grid2Options = reactive(gridProps({
height: '100%',
size: 'mini',
columns: getColumns({ todoType: 'done' }),
proxyConfig: {
autoLoad: true,
ajax: {
query: ({ page }) => {
return Apis.ccsq.get_donePage({ params: { pageNum: page.currentPage, pageSize: page.pageSize, ...searchParams } })
}
const grid2Options = reactive(
gridProps({
height: '100%',
size: 'mini',
columns: getColumns({ todoType: 'done' }),
proxyConfig: {
autoLoad: true,
ajax: {
query: ({ page }) => {
return Apis.ccsq.get_donePage({
params: {
pageNum: page.currentPage,
pageSize: page.pageSize,
...searchParams,
},
});
},
},
},
},
pagerConfig: {
enabled: true
},
toolbarConfig: {
enabled: false
},
}));
pagerConfig: {
enabled: true,
},
toolbarConfig: {
enabled: false,
},
}),
);
onMounted(() => {});
onMounted(() => {
})
let searchParams = reactive({})
let searchParams = reactive({});
const searchForm = ref({
columns: {
name: {
@ -102,47 +117,46 @@ const searchForm = ref({
},
},
onSearch(context: any) {
searchParams = context.form
triggerProxy('reload')
searchParams = context.form;
triggerProxy('reload');
},
onReset(context: any) {
searchParams = context.form
searchParams = context.form;
},
});
let isConfirmLoading = ref(false)
let isConfirmLoading = ref(false);
const [TemporaryModalApi, temporaryModalApi] = useVbenModal({
onOpenChange(isOpen: boolean) {
if (isOpen) {
isConfirmLoading.value = false
isConfirmLoading.value = false;
}
},
async onConfirm() {
// await
}
})
},
});
async function handleAudit(row, type) {
selectRow.value = row
selectRow.value = row;
if (type === 'access') {
chooseUserModalApi.setData({
title: "选择审批人",
})
chooseUserModalApi.open()
return
title: '选择审批人',
});
chooseUserModalApi.open();
return;
}
if (type === 'reject') {
await Apis.ccsq.get_getBackNode({
params: { taskId: row.taskId }
})
params: { taskId: row.taskId },
});
form2Binding.value.columns = {}
form2Binding.value.columns = {};
title.value = "审核拒绝";
title.value = '审核拒绝';
form2Binding.value.columns = {
comment: {
title: '',
@ -152,17 +166,16 @@ async function handleAudit(row, type) {
component: {
name: 'a-time-picker',
vModel: 'value',
format: "HH:mm",
valueFormat: "HH:mm",
format: 'HH:mm',
valueFormat: 'HH:mm',
},
},
}
};
temporaryModalApi.open()
temporaryModalApi.open();
nextTick(() => {
form2Ref.value.setFormData(submitForm.value)
})
form2Ref.value.setFormData(submitForm.value);
});
}
}
@ -173,20 +186,19 @@ async function handleChooseUserConfirm(e) {
await Apis.ccsq.post_submit({
data: {
guid: selectRow.value.guid,
assigneeList: e.map(item => item.ACCOUNT_ID),
comment:"通过"
}
})
message.success("提交成功")
assigneeList: e.map((item) => item.ACCOUNT_ID),
comment: '通过',
},
});
message.success('提交成功');
} catch (error) {
console.log(error)
message.error("提交失败,请稍候再试")
console.log(error);
message.error('提交失败,请稍候再试');
} finally {
}
}
const title = ref("1");
const title = ref('1');
const form2Ref = ref();
@ -194,23 +206,33 @@ const form2Binding = ref({
col: { span: 24 },
columns: {},
});
</script>
<template>
<Page contentClass="h-full flex flex-col">
<TemporaryModal class="w-[400px]" :title="title" contentClass="min-h-0" :loading="isConfirmLoading"
:confirmLoading="isConfirmLoading">
<TemporaryModal
class="w-[400px]"
:title="title"
contentClass="min-h-0"
:loading="isConfirmLoading"
:confirmLoading="isConfirmLoading"
>
<fs-form ref="form2Ref" v-bind="form2Binding"> </fs-form>
</TemporaryModal>
<ChooseUserModal class="w-[950px]" multiple @confirm="handleChooseUserConfirm" />
<ChooseUserModal
class="w-[950px]"
multiple
@confirm="handleChooseUserConfirm"
/>
<a-space direction="vertical" size="small" class="h-full flex flex-col">
<a-card title="待办" size="small" class="h-full flex flex-col" :bodyStyle="{ 'flex': '1' }">
<a-space direction="vertical" size="small" class="flex h-full flex-col">
<a-card
title="待办"
size="small"
class="flex h-full flex-col"
:bodyStyle="{ flex: '1' }"
>
<vxe-grid ref="xGridRef" v-bind="gridOptions" class="h-full">
<template #toolbar_buttons> </template>
@ -221,32 +243,45 @@ const form2Binding = ref({
<template #operate="{ row }">
<a-space>
<a-button type="text" size="small" @click="handleAudit(row, 'access')">
<a-button
type="text"
size="small"
@click="handleAudit(row, 'access')"
>
通过
</a-button>
<a-button type="text" danger size="small" @click="handleAudit(row, 'reject')">
<a-button
type="text"
danger
size="small"
@click="handleAudit(row, 'reject')"
>
拒绝
</a-button>
</a-space>
</template>
</vxe-grid>
</a-card>
<a-card title="已办" size="small" class="h-full flex flex-col" :bodyStyle="{ 'flex': '1' }">
<a-card
title="已办"
size="small"
class="flex h-full flex-col"
:bodyStyle="{ flex: '1' }"
>
<vxe-grid ref="xGrid2Ref" v-bind="grid2Options">
<template #toolbar_buttons> </template>
<template #baseSlot="{ row }">
<p>开始时间{{ row.starttime }}</p>
<p>结束时间{{ row.endtime }}</p>
</template>
</vxe-grid>
</a-card>
</a-space>
</Page>
</template>
<style>
.ant-space-item {
<style scoped>
:deep(.ant-space-item) {
flex: 1;
}
</style>

View File

@ -58,13 +58,13 @@
</template>
<template #unitSlot="{ row }">
<p
<span
v-if="row.idNumber"
class="cursor-pointer hover:color-blue hover:underline"
@click="toDetail(row)"
>
{{ row.name + "-" + row.idNumber }}
</p>
</span>
<p v-else>{{ row.unit }}</p>
</template>
</vxe-grid>

View File

@ -15,8 +15,17 @@ import { getFormSchema } from "./curd";
import { FileUploader } from "#/utils/file";
import { DICT_TYPE, getDictObj, getDictOptions } from "#/utils/dict";
import { useVxeTable } from "#/hooks/vxeTable";
import chooseSigningBasisModal from "../signing-basis/choose-signing-basis-modal.vue";
import { useRender } from "#/hooks/useRender";
const { xGridRef, gridProps, triggerProxy } = useVxeTable({ ref: "xGridRef" });
const [ChooseSigningBasisModal, chooseSigningBasisModalApi] = useVbenModal({
connectedComponent: chooseSigningBasisModal,
});
const fileUploader = new FileUploader({})
const router = useRouter();
@ -44,24 +53,49 @@ const formBinding = ref({
columns: {}
});
function getColumns(): any {
function getColumns(params): any {
return [
{ type: "seq", title: "序号", width: 60 },
{ field: "referenceName", title: "签约依据名称", minWidth: 150 },
{ field: "referenceId", title: "签约依据编号", width: 200 },
{ field: "attachments", title: "附件", width: 120 },
{ field: 'basisId', title: '依据号', width: 130 },
{
field: 'basisName',
title: '依据名称',
width: 200,
},
{ field: 'basisNum', title: '依据编号', width: 180 },
{
field: 'basisTypeId',
title: '依据类型',
width: 100,
slots: {
default: ({ row }) => {
return getDictObj(DICT_TYPE.contractBasisType, row.basisTypeId)
?.label;
},
},
},
{
field: 'endDate',
title: '有效期',
width: 150,
slots: {
default: ({ row }) => {
return useRender.renderDate(row.endDate, 'YYYY-MM-DD');
},
},
},
{
title: "操作",
width: 120,
slots: { default: "operation" },
slots: { default: "operate" },
},
];
}
/** Hooks - 表格 */
const gridOptions = reactive(gridProps({
minHeight: "300px",
columns: getColumns(),
height: "200px",
columns: getColumns({ isMultiple: true }),
data: [],
toolbarConfig: {
enabled: false,
@ -112,8 +146,8 @@ function back() {
router.replace('/contract/approval/list')
}
function handleOpenSignBasisModal(row) {
function handleOpenSignBasisChooseModal(row) {
chooseSigningBasisModalApi.open()
}
const handleChange = (info: UploadChangeParam) => {
@ -156,6 +190,18 @@ function loadDataByContractTypeData() {
}
function handleChooseConfirm(rows) {
const $grid = xGridRef.value;
//
if ($grid) {
$grid.remove();
$grid.insert(rows).then(({ row }) => { });
} else {
console.error("xGridRef不存在");
}
}
async function handleSave() {
isLoading.value = true
@ -210,18 +256,30 @@ async function handleSave() {
console.log(newForm)
await Apis.contractBaseInfo.post_apply({ data: newForm }).then((data) => {
message.success("保存成功");
Modal.confirm({
title: "提示",
content: "保存成功!是否进行提交?",
onOk: () => {
handleSubmit()
},
onCancel: () => {
back();
},
});
let result = await Apis.contractBaseInfo.post_apply({ data: newForm });
return
//
let tableFullData = xGridRef.value?.getTableData().fullData
if (tableFullData && tableFullData.length) {
newForm.guid = result.data.guid
newForm.basisId = tableFullData[0].basisId
await Apis.contractBaseInfo.post_apply({ data: newForm })
}
console.log(result)
message.success("保存成功");
Modal.confirm({
title: "提示",
content: "保存成功!是否进行提交?",
onOk: () => {
handleSubmit()
},
onCancel: () => {
back();
}
});
} catch (error) {
message.error("提交失败,请稍候再试");
@ -255,10 +313,6 @@ onMounted(async () => {
isLoading.value = true
console.log(id)
// let formSchema = getFormSchema()
// formBinding.value = formSchema
try {
let contractReferTypeData = await Apis.contractReferType.get_list({ params: {} })
@ -269,7 +323,7 @@ onMounted(async () => {
})
if (id) {
let data = await Apis.contractBaseInfo.get_getOne({ params: { guid: id } })
let data:any = await Apis.contractBaseInfo.get_getOne({ params: { guid: id } })
console.log(data)
currData.value = data;
@ -277,6 +331,14 @@ onMounted(async () => {
formRef.value.setFormData(data)
})
//
if(data.basisId){
let basisList = await Apis.lxBasisSale.get_page({params:{basisId:data.basisId}})
nextTick(() => {
xGridRef.value.insert(basisList.rows)
})
}
if (data.fileUuid) {
let files = await fileUploader.select(data.fileUuid)
console.log(files)
@ -311,6 +373,8 @@ onMounted(async () => {
<template>
<Page ref="pageRef" contentClass="h-full flex flex-col">
<ChooseSigningBasisModal class="w-[950px]" @confirm="handleChooseConfirm" />
<a-affix :target="() => pageRef.bodyRef" :offset-top="0" :style="{ zIndex: 50 }">
<div class="bg-white w-full flex flex-row pt-1 pl-1">
<a-space class="flex-1">
@ -346,7 +410,7 @@ onMounted(async () => {
<a-collapse-panel key="2" header="签约依据" class="w-full">
<template #extra>
<a-button size="small" type="primary" @click="handleOpenSignBasisModal()">
<a-button size="small" type="primary" @click.stop="handleOpenSignBasisChooseModal()">
<MdiAdd class="text-lg mr-0.5" />
选择签约依据
</a-button>
@ -356,10 +420,6 @@ onMounted(async () => {
<template #toolbar_buttons></template>
<template #operate="{ row }">
<a-space>
<a-button type="text" class="text-yellow-500" size="small" @click="handleOpenSignBasisModal(row)">
编辑
</a-button type="text">
<a-button type="text" class="text-red-500" size="small" @click="removeRow(row)">
移除
</a-button type="text">
@ -378,9 +438,9 @@ onMounted(async () => {
<style scoped>
.sortable-tree-demo .drag-btn {
cursor: move;
font-size: 12px;
text-align: center;
cursor: move;
}
.sortable-tree-demo .vxe-body--row.sortable-ghost,

View File

@ -11,14 +11,8 @@ import { message } from "ant-design-vue";
import { Modal } from 'ant-design-vue';
import { toDetailPage } from '#/views/contract/utils.ts';
import { useRouter } from 'vue-router'
import chooseSigningBasisModal from '../signing-basis/choose-signing-basis-modal.vue';
const router = useRouter();
const [ChooseSigningBasisModal, chooseSigningBasisModalApi] = useVbenModal({
connectedComponent: chooseSigningBasisModal,
});
const searchRef = ref()
const searchFormBinding = ref({
@ -103,17 +97,6 @@ function handleCellClick({ row }) {
setSelectRow(row);
}
function handleChooseConfirm(e) {
const $grid = xGridRef.value;
//
if ($grid) {
$grid.remove();
$grid.insert(rows).then(({ row }) => { });
} else {
console.error("xGridRef不存在");
}
}
onMounted(async () => {
triggerProxy('reload')
@ -124,8 +107,6 @@ onMounted(async () => {
<template>
<Page contentClass="h-full flex flex-col">
<ChooseSigningBasisModal class="w-[950px]" @confirm="handleChooseConfirm" />
<fs-search ref="searchRef" v-bind="searchFormBinding">
<template #form_price="{ row }">
<a-input-number v-model:value="row.budgetSum1" placeholder="">

View File

@ -47,7 +47,7 @@ const searchBinding = ref({
const gridOptions = reactive(
gridProps({
height: "400px",
columns: getColumns(),
columns: getColumns({ type: 'choose' }),
pagerConfig: { size: "mini" },
proxyConfig: {
autoLoad: true,
@ -72,7 +72,7 @@ const gridOptions = reactive(
keyField: "basisId",
},
checkboxConfig: {
labelField: "basisName",
labelField: "basisId",
//
showHeader: false,
highlight: true,
@ -81,7 +81,7 @@ const gridOptions = reactive(
reserve: true,
checkMethod: ({ row }) => {
let checkRecordIds = checkRecords.value.map((item) => item.guid);
if (checkRecords.value.length < 10 || checkRecordIds.includes(row.guid)) {
if (checkRecords.value.length < 1 || checkRecordIds.includes(row.guid)) {
return true;
}
return false;
@ -118,8 +118,8 @@ function handleCheckboxChange(e) {
}
console.log("[ checkRecords.value ] >", checkRecords.value);
if (allRows.length >= 10) {
messageApi.warning("最多只能选择10条数据");
if (allRows.length >= 1) {
messageApi.warning("最多只能选择1条数据");
}
}

View File

@ -1,50 +1,106 @@
import type { VxeGridPropTypes } from 'vxe-table';
import { useRender } from '#/hooks/useRender';
import { DICT_TYPE, getDictOptions } from '#/utils/dict';
import { DICT_TYPE, getDictObj, getDictOptions } from '#/utils/dict';
import { dict } from '@fast-crud/fast-crud';
export const PrimaryKey = 'guid';
export function getColumns(_params: any = {}): VxeGridPropTypes.Columns {
let columns: VxeGridPropTypes.Columns = [
{ field: 'basisId', title: '依据号', width: 130 },
{
field: 'basisName',
title: '依据名称',
width: 200,
},
{ field: 'basisNum', title: '依据编号', width: 180 },
{
field: 'basisTypeId', title: '依据类型', width: 100, slots: {
default: ({ row }) => {
return useRender.renderDict(row.basisTypeId, DICT_TYPE.contractBasisType);
}
}
},
{
field: 'endDate', title: '有效期', width: 150, slots: {
default: ({ row }) => {
return useRender.renderDate(row.endDate, 'YYYY-MM-DD');
}
}
},
{ field: 'inputPerson', title: '创建人', width: 150 },
{
field: 'inputDate', title: '创建时间', width: 150, slots: {
default: ({ row }) => {
return useRender.renderDate(row.inputDate, 'YYYY-MM-DD');
}
}
},
{ field: 'remark', title: '备注', minWidth: 200 },
]
export function getColumns(params: any = {}): VxeGridPropTypes.Columns {
let columns: VxeGridPropTypes.Columns = [];
if (params.type === 'choose') {
columns = [
{ field: 'basisId', title: '依据号', type: 'checkbox', width: 160 },
{
field: 'basisName',
title: '依据名称',
width: 200,
},
{ field: 'basisNum', title: '依据编号', width: 180 },
{
field: 'basisTypeId',
title: '依据类型',
width: 100,
slots: {
default: ({ row }) => {
return getDictObj(DICT_TYPE.contractBasisType, row.basisTypeId)
?.label;
},
},
},
{
field: 'endDate',
title: '有效期',
width: 150,
slots: {
default: ({ row }) => {
return useRender.renderDate(row.endDate, 'YYYY-MM-DD');
},
},
},
{ field: 'inputPerson', title: '创建人', width: 150 },
{
field: 'inputDate',
title: '创建时间',
width: 150,
slots: {
default: ({ row }) => {
return useRender.renderDate(row.inputDate, 'YYYY-MM-DD');
},
},
},
{ field: 'remark', title: '备注', minWidth: 200 },
];
} else {
columns = [
{ field: 'basisId', title: '依据号', width: 130 },
{
field: 'basisName',
title: '依据名称',
width: 200,
},
{ field: 'basisNum', title: '依据编号', width: 180 },
{
field: 'basisTypeId',
title: '依据类型',
width: 100,
slots: {
default: ({ row }) => {
return getDictObj(DICT_TYPE.contractBasisType, row.basisTypeId)
?.label;
},
},
},
{
field: 'endDate',
title: '有效期',
width: 150,
slots: {
default: ({ row }) => {
return useRender.renderDate(row.endDate, 'YYYY-MM-DD');
},
},
},
{ field: 'inputPerson', title: '创建人', width: 150 },
{
field: 'inputDate',
title: '创建时间',
width: 150,
slots: {
default: ({ row }) => {
return useRender.renderDate(row.inputDate, 'YYYY-MM-DD');
},
},
},
{ field: 'remark', title: '备注', minWidth: 200 },
];
}
return columns;
}
export function getFormSchema(_params: any = {}) {
return {
initialForm: {
},
initialForm: {},
columns: {
basisName: {
title: '依据名称',

View File

@ -2,114 +2,110 @@
import { ref, computed, reactive, onMounted } from 'vue';
import { Page, useVbenModal } from '@vben/common-ui';
import { useVxeTable } from '#/hooks/vxeTable';
import { MdiAdd, MdiUpdate, MdiDelete, MdiImport, MdiExport, MdiRadioUnchecked, MdiRadioChecked } from '@vben/icons';
import {
MdiAdd,
MdiUpdate,
MdiDelete,
MdiImport,
MdiExport,
MdiRadioUnchecked,
MdiRadioChecked,
} from '@vben/icons';
import { getFormSchema, getColumns, PrimaryKey } from './crud.tsx';
import { getMonthStartAndEnd } from '#/utils/time'
import Apis from '#/api'
import { getMonthStartAndEnd } from '#/utils/time';
import Apis from '#/api';
import dayjs from 'dayjs';
import { message } from "ant-design-vue";
import { message } from 'ant-design-vue';
import { Modal } from 'ant-design-vue';
import { toDetailPage } from '#/views/contract/utils.ts';
import { useRouter } from 'vue-router'
import { useRouter } from 'vue-router';
const router = useRouter();
const checkedValue = ref('all')
const checkedValue = ref('all');
const exportSearchParams = ref<any>({
daterange: getMonthStartAndEnd(),
});
const searchRef = ref()
let isConfirmLoading = ref(false)
const searchRef = ref();
let isConfirmLoading = ref(false);
const [_Modal, modalApi] = useVbenModal({
async onConfirm() {
isConfirmLoading.value = true
isConfirmLoading.value = true;
try {
let params = {};
if (checkedValue.value == "daterange") {
if (checkedValue.value == 'daterange') {
params = {
startDate: exportSearchParams.value.daterange[0],
endDate: exportSearchParams.value.daterange[1],
};
}
let res = await Apis.zbgl.post_export({
params: params, config: {
meta: {
responseType: 'blob'
}
}
}).send();
message.success("导出成功");
modalApi.close()
let res = await Apis.zbgl
.post_export({
params: params,
config: {
meta: {
responseType: 'blob',
},
},
})
.send();
message.success('导出成功');
modalApi.close();
showExportModal.value = false;
} catch (error) {
console.error(error);
} finally {
isConfirmLoading.value = false
isConfirmLoading.value = false;
}
console.info("onConfirm");
console.info('onConfirm');
},
});
const { xGridRef, triggerProxy, gridProps } = useVxeTable({ ref: 'xGridRef' });
const treeData = ref([]);
/** Hooks - 表格 */
const gridOptions = reactive(gridProps({
columns: getColumns(),
proxyConfig: {
autoLoad: false,
ajax: {
query: ({ page }) => {
return Apis.contractBaseInfo.get_page({ params: { pageNum: page.currentPage, pageSize: page.pageSize, ...searchRef.value?.formData } })
}
const gridOptions = reactive(
gridProps({
columns: getColumns(),
proxyConfig: {
autoLoad: false,
ajax: {
query: ({ page }) => {
return Apis.contractBaseInfo.get_page({
params: {
pageNum: page.currentPage,
pageSize: page.pageSize,
...searchRef.value?.formData,
},
});
},
},
},
},
pagerConfig: {
enabled: true
},
toolbarConfig: {
enabled: true
},
}));
pagerConfig: {
enabled: true,
},
toolbarConfig: {
enabled: true,
},
}),
);
function handleEdit(record?: any) {
if (record && record[PrimaryKey]) {
router.push("/contract/business/edit/" + record[PrimaryKey]);
} else {
router.push("/contract/business/edit");
}
}
function handleDelete(row) {
Modal.confirm({
title: '提示',
content: "是否确认删除该条记录?",
okType: 'danger',
onOk: async () => {
await Apis.contractBaseInfo.post_deletes({ params: { ids: row[PrimaryKey] } })
message.success("删除成功");
triggerProxy("reload");
},
onCancel() {
console.log('Cancel');
},
});
router.push('/contract/business/edit/' + record[PrimaryKey]);
}
function handleExport() {
const $grid = xGridRef.value;
if ($grid) {
$grid.exportData({
type: "xlsx",
type: 'xlsx',
});
message.success("导出成功");
message.success('导出成功');
}
}
@ -133,23 +129,22 @@ function handleCellClick({ row }) {
}
onMounted(() => {
triggerProxy('reload')
})
triggerProxy('reload');
});
const searchForm = ref({
...getFormSchema(),
onSearch(context: any) {
triggerProxy('reload')
}
triggerProxy('reload');
},
});
function toPage() {
window.open("/iframe/meeting/standing-book", "_blank");
window.open('/iframe/meeting/standing-book', '_blank');
}
function toDetail(row) {
window.open("/iframe/meeting/start/" + row.guid, "_blank");
window.open('/iframe/meeting/start/' + row.guid, '_blank');
}
//
</script>
@ -165,36 +160,44 @@ function toDetail(row) {
</a-input-number>
</template>
<template #form_time="{ row }">
<a-date-picker v-model:value="row.startTime" placeholder="" format="YYYY-MM-DD" value-format="YYYY-MM-DD">
<a-date-picker
v-model:value="row.startTime"
placeholder=""
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
>
</a-date-picker>
<span class="mx-1"></span>
<a-date-picker v-model:value="row.endTime" placeholder="" format="YYYY-MM-DD" value-format="YYYY-MM-DD">
<a-date-picker
v-model:value="row.endTime"
placeholder=""
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
>
</a-date-picker>
</template>
</fs-search>
<div class="flex-1 min-h-300px">
<vxe-grid ref="xGridRef" v-bind="gridOptions" @cell-click="handleCellClick">
<div class="min-h-300px flex-1">
<vxe-grid
ref="xGridRef"
v-bind="gridOptions"
@cell-click="handleCellClick"
>
<template #toolbar_buttons>
<a-space>
<vben-button variant="primary" @click="handleEdit()">
<MdiAdd class="text-lg mr-0.5" />
新增
</vben-button>
<vben-button variant="warning" :disabled="!selectRow || !selectRow[PrimaryKey]"
@click="handleEdit(selectRow)">
<MdiUpdate class="text-lg mr-0.5" />
<vben-button
variant="warning"
:disabled="!selectRow || !selectRow[PrimaryKey]"
@click="handleEdit(selectRow)"
>
<MdiUpdate class="mr-0.5 text-lg" />
修改
</vben-button>
<vben-button variant="primary" @click="handleExport()">
<MdiExport class="text-lg mr-0.5" />
<MdiExport class="mr-0.5 text-lg" />
导出
</vben-button>
<vben-button variant="destructive" :disabled="!selectRow || !selectRow[PrimaryKey]"
@click="handleDelete(selectRow)">
<MdiDelete class="text-lg mr-0.5" />
删除
</vben-button>
</a-space>
</template>
@ -206,15 +209,18 @@ function toDetail(row) {
</template>
<template #contract-name-slot="{ row }">
<span class=""> {{ row.contractName }}</span>
<span class=""> {{ row.contractName }}</span>
</template>
<template #operate="{ row }">
<a-button type="primary" size="small" @click="toDetailPage('business', row.guid)">
<a-button
type="primary"
size="small"
@click="toDetailPage('business', row.guid)"
>
查看
</a-button>
</template>
</vxe-grid>
</div>
</Page>

View File

@ -1,181 +1,386 @@
import { DICT_TYPE, getDictOptions } from "#/utils/dict";
import { dict } from "@fast-crud/fast-crud";
/**
*
*
*/
function filterContractTypes(contractTypeData: any = [], parentId: string) {
return contractTypeData.map((item) => {
item.label = item.contrLevelName;
item.value = item.contrLevelId;
return item;
}).filter((item) => item.parentId === parentId);
}
export function getFormSchema(params: any = {}) {
const { contractTypeData } = params
import { DICT_TYPE, getDictOptions } from '#/utils/dict';
import { dict } from '@fast-crud/fast-crud';
export function getFormSchema(_params: any = {}) {
return {
contractName: {
title: "合同名称",
key: "contractName",
col: { span: 24 },
component: {
name: "a-input",
vModel: "value",
allowClear: false,
labelCol: { style: { width: '140px' } },
columns: {
providerName: {
title: '单位全称',
key: 'providerName',
col: { span: 12 },
component: {
name: 'a-input',
vModel: 'value',
allowClear: false,
},
rules: [{ required: true }],
},
rules: [{ required: true }],
},
ctrType: {
title: "合同类别",
key: "ctrType",
col: { span: 12 },
component: {
name: "fs-dict-select",
vModel: "value",
class: 'min-w-[200px]',
dict: dict({
async getData({ form = {} }) {
return filterContractTypes(contractTypeData, "-1");
},
}),
providerKind: {
title: '性质',
key: 'providerKind',
col: { span: 12 },
component: {
name: 'fs-dict-select',
vModel: 'value',
class: 'min-w-[200px]',
dict: dict({
data: [],
}),
},
rules: [{ required: true }],
},
valueChange({ form, value, getComponentRef }) {
form.ctrTwoType = undefined;
if (value) {
getComponentRef("ctrTwoType").reloadDict(); // 执行city的select组件的reloadDict()方法触发“city”重新加载字典
}
providerAddr: {
title: '住所',
key: 'providerAddr',
col: { span: 12 },
component: {
name: 'a-input',
vModel: 'value',
allowClear: false,
},
},
rules: [{ required: true }],
},
ctrTwoType: {
title: "二级类别",
key: "ctrTwoType",
col: { span: 12 },
component: {
name: "fs-dict-select",
vModel: "value",
class: 'min-w-[200px]',
dict: dict({
async getData({ form = {} }) {
return filterContractTypes(contractTypeData, form.ctrType);
},
}),
businessCode: {
title: '营业执照注册号',
key: 'businessCode',
col: { span: 12 },
component: {
name: 'a-input',
vModel: 'value',
allowClear: false,
},
},
rules: [{ required: true }],
},
frameProtocol: {
title: "框架协议",
key: "frameProtocol",
col: { span: 8 },
component: {
name: "fs-dict-radio",
vModel: "value",
dict: dict({
data: [
{ label: "是", value: 1, },
{ label: "否", value: 0 },
]
}),
juridicalPerson: {
title: '法人姓名',
key: 'juridicalPerson',
col: { span: 12 },
component: {
name: 'a-input',
vModel: 'value',
allowClear: false,
},
},
taxNo: {
title: '税务登记证号',
key: 'taxNo',
col: { span: 12 },
component: {
name: 'a-input',
vModel: 'value',
allowClear: false,
},
},
organizeNum: {
title: '组织机构代码',
key: 'organizeNum',
col: { span: 12 },
component: {
name: 'a-input',
vModel: 'value',
allowClear: false,
},
},
creditCode: {
title: '统一社会信用代码',
key: 'creditCode',
col: { span: 12 },
component: {
name: 'a-input',
vModel: 'value',
allowClear: false,
},
},
registerMoney: {
title: '注册资金',
key: 'registerMoney',
col: { span: 12 },
component: {
name: 'a-input-number',
vModel: 'value',
allowClear: false,
},
},
currencyTypeId: {
title: '币种',
key: 'currencyTypeId',
col: { span: 12 },
component: {
name: 'fs-dict-select',
vModel: 'value',
dict: dict({
data: getDictOptions(DICT_TYPE.contractCurrencyUnit),
}),
},
},
marketScope: {
title: '营业执照经营范围',
key: 'marketScope',
col: { span: 24 },
component: {
name: 'a-textarea',
vModel: 'value',
autosize: { minRows: 4, maxRows: 6 },
},
},
},
frameProtocolCtr: {
title: "框架协议下的合同",
key: "frameProtocolCtr",
col: { span: 12 },
labelCol: { style: { width: "200px" } },
component: {
name: "fs-dict-radio",
vModel: "value",
dict: dict({
data: [
{ label: "是", value: 1, },
{ label: "否", value: 0 },
]
}),
},
},
fundAllocation: {
title: "资金流向",
key: "fundAllocation",
col: { span: 12 },
component: {
name: "fs-dict-select",
vModel: "value",
allowClear: false,
class: 'min-w-[200px]',
dict: dict({
data: getDictOptions(DICT_TYPE.contractFundFlow)
}),
},
rules: [{ required: true, message: "请选择资金流向" }],
},
fundDitch: {
title: "资金渠道",
key: "fundDitch",
col: { span: 12 },
component: {
name: "fs-dict-select",
vModel: "value",
allowClear: false,
class: 'min-w-[200px]',
dict: dict({
data: getDictOptions(DICT_TYPE.contractFundingSource)
}),
},
rules: [{ required: true, message: "请选择资金渠道" }],
},
budgetSum: {
title: '预算金额',
key: 'budgetSum',
col: { span: 8 },
colon: false,
component: {
name: 'a-input-number',
vModel: 'value',
class: 'w-full',
min: 0,
max: 9999,
},
},
priceType: {
title: '',
key: 'priceType',
col: { span: 6 },
labelCol: { style: { width: "12px" } },
colon: false,
component: {
name: 'fs-dict-select',
vModel: 'value',
dict: dict({
data: getDictOptions(DICT_TYPE.contractCurrencyUnit)
}),
},
},
organiza: {
title: "组织形式",
key: "organiza",
col: { span: 12 },
component: {
name: "fs-dict-select",
vModel: "value",
allowClear: false,
class: 'min-w-[200px]',
dict: dict({
data: getDictOptions(DICT_TYPE.contractOrganizationForm)
}),
},
rules: [{ required: true, message: "请选择组织形式" }],
},
fileList: {
title: "相关附件",
key: "fileList",
},
}
};
}
export function getFormSchemaByBank(_params: any = {}) {
return {
labelCol: { style: { width: '140px' } },
initialForm: {
isOutside: 0,
},
columns: {
accountBank: {
title: '开户银行',
key: 'accountBank',
col: { span: 12 },
component: {
name: 'a-input',
vModel: 'value',
allowClear: false,
},
},
bankAccount: {
title: '银行账号',
key: 'bankAccount',
col: { span: 12 },
component: {
name: 'a-input',
vModel: 'value',
allowClear: false,
},
},
bankNetwork: {
title: '开户银行网点',
key: 'bankNetwork',
col: { span: 12 },
component: {
name: 'a-input',
vModel: 'value',
allowClear: false,
},
},
bankNetworkAddr: {
title: '银行网点地址',
key: 'bankNetwork',
col: { span: 12 },
component: {
name: 'a-input',
vModel: 'value',
allowClear: false,
},
},
linkPerson: {
title: '联系人',
key: 'linkPerson',
col: { span: 12 },
component: {
name: 'a-input',
vModel: 'value',
allowClear: false,
},
},
linkPhone: {
title: '联系人电话',
key: 'linkPhone',
col: { span: 12 },
component: {
name: 'a-input',
vModel: 'value',
allowClear: false,
},
},
fax: {
title: '传真',
key: 'fax',
col: { span: 12 },
component: {
name: 'a-input',
vModel: 'value',
allowClear: false,
},
},
email: {
title: '电子邮件',
key: 'email',
col: { span: 12 },
component: {
name: 'a-input',
vModel: 'value',
allowClear: false,
},
},
isOutside: {
title: '是否境外主体',
key: 'isOutside',
col: { span: 24 },
component: {
name: 'fs-dict-radio',
vModel: 'value',
dict: dict({
data: [
{ label: '否', value: 0 },
{ label: '是', value: 1 },
],
}),
},
},
customerCode: {
title: 'MDM客户编码',
key: 'customerCode',
col: { span: 12 },
component: {
name: 'a-input',
vModel: 'value',
allowClear: false,
},
},
vendorCoding: {
title: 'MDM供应商编码',
key: 'vendorCoding',
col: { span: 12 },
component: {
name: 'a-input',
vModel: 'value',
allowClear: false,
},
},
remark: {
title: '备注',
key: 'remark',
col: { span: 24 },
component: {
name: 'a-textarea',
vModel: 'value',
autosize: { minRows: 4, maxRows: 6 },
},
},
},
};
}
export function getFormSchemaByCertification(params: any = {}) {
return {
labelCol: { style: { width: '140px' } },
initialForm: {},
columns: {
aptitudeName: {
title: '资质名称',
key: 'aptitudeName',
col: { span: 12 },
component: {
name: 'a-input',
vModel: 'value',
allowClear: false,
},
},
aptitudeGrade: {
title: '资质等级',
key: 'aptitudeGrade',
col: { span: 12 },
component: {
name: 'a-input',
vModel: 'value',
allowClear: false,
},
},
time: {
title: '有效期',
key: 'time',
col: { span: 12 },
render({ form }) {
//注意此处的v-model写法
return (
<div class="flex">
<a-form-item class="!mb-0 inline-block">
<a-date-picker
v-model:value={form.aptitudeBeginDate}
placeholder=""
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
/>
</a-form-item>
<span class="mx-1"></span>
<a-form-item class="!mb-0 inline-block">
<a-date-picker
v-model:value={form.aptitudeEndDate}
placeholder=""
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
/>
</a-form-item>
</div>
);
},
},
fileList: {
title: '相关资质附件',
key: 'fileList',
col: { span: 24 },
},
aptitudeRemark: {
title: '备注',
key: 'aptitudeRemark',
col: { span: 24 },
component: {
name: 'a-textarea',
vModel: 'value',
autosize: { minRows: 4, maxRows: 6 },
},
},
},
};
}
export function getFormSchemaByShareholder(params: any = {}) {
return {
labelCol: { style: { width: '140px' } },
columns: {
shareholderName: {
title: '股东名称',
key: 'shareholderName',
col: { span: 12 },
component: {
name: 'a-input',
vModel: 'value',
allowClear: false,
},
},
shareholderIdCard: {
title: '股东身份证号',
key: 'shareholderIdCard',
col: { span: 12 },
component: {
name: 'a-input',
vModel: 'value',
allowClear: false,
},
},
shareholderTypeId: {
title: '类型',
key: 'shareholderIdCard',
col: { span: 12 },
component: {
name: 'fs-dict-select',
vModel: 'value',
dict: dict({
data: [],
}),
},
},
investmentRate: {
title: '出资比例',
key: 'investmentRate',
col: { span: 12 },
component: {
name: 'a-input',
vModel: 'value',
allowClear: false,
},
},
},
};
}

View File

@ -1,88 +1,81 @@
<script setup lang="ts">
import { ref, computed, reactive, onMounted, nextTick, onUnmounted } from "vue";
import { ref, computed, reactive, onMounted, nextTick, onUnmounted } from 'vue';
import { MdiAdd } from '@vben/icons';
import { Page, useVbenModal } from "@vben/common-ui";
import { dict, type FormScopeContext } from "@fast-crud/fast-crud";
import { MdiUpload } from "@vben/icons";
import { useRouter } from 'vue-router'
import dayjs, { Dayjs } from "dayjs";
import Apis from "#/api";
import { message, Modal, type UploadChangeParam, type UploadProps } from 'ant-design-vue';
import { useUserStore } from "@vben/stores";
import { useRoute } from "vue-router";
import { getFormSchema } from "./curd";
import { FileUploader } from "#/utils/file";
import { DICT_TYPE, getDictObj, getDictOptions } from "#/utils/dict";
import { useVxeTable } from "#/hooks/vxeTable";
const { xGridRef, gridProps, triggerProxy } = useVxeTable({ ref: "xGridRef" });
import { Page, useVbenModal } from '@vben/common-ui';
import { dict, type FormScopeContext } from '@fast-crud/fast-crud';
import { MdiUpload } from '@vben/icons';
import { useRouter } from 'vue-router';
import dayjs, { Dayjs } from 'dayjs';
import Apis from '#/api';
import {
message,
Modal,
type UploadChangeParam,
type UploadFile,
} from 'ant-design-vue';
import { useUserStore } from '@vben/stores';
import { useRoute } from 'vue-router';
import {
getFormSchema,
getFormSchemaByBank,
getFormSchemaByCertification,
getFormSchemaByShareholder,
} from './curd';
import { FileUploader } from '#/utils/file';
import { DICT_TYPE, getDictObj, getDictOptions } from '#/utils/dict';
import { useVxeTable } from '#/hooks/vxeTable';
const fileUploader = new FileUploader({})
const fileUploader = new FileUploader({});
const router = useRouter();
const route = useRoute();
const id = route.params.id;
const pageRef = ref();
let showHelpTip = ref(false);
const containerRef = ref();
const formRef = ref();
const form2Ref = ref();
const formRefByBank = ref();
const formRefByCertification = ref();
const formRefByShareholder = ref();
let isLoading = ref(false)
let contractTypeData = ref([])
let isLoading = ref(false);
let contractTypeData = ref([]);
const formBinding = ref({
col: { span: 24 },
initialForm: {
contractName: '',
priceType: 'CNY'
},
labelCol: { style: { width: "120px" } },
columns: {}
...getFormSchema(),
});
function getColumns(): any {
return [
{ type: "seq", title: "序号", width: 60 },
{ field: "referenceName", title: "签约依据名称", minWidth: 150 },
{ field: "referenceId", title: "签约依据编号", width: 200 },
{ field: "attachments", title: "附件", width: 120 },
{
title: "操作",
width: 120,
slots: { default: "operation" },
},
];
const formBindingByBank = ref({
...getFormSchemaByBank(),
});
const formBindingByCertification = ref({
...getFormSchemaByCertification(),
});
const formBindingByShareholder = ref({
...getFormSchemaByShareholder(),
});
let collapses = ['1', '2', '3', '4', '5'];
let collapseActiveKey = ref(collapses);
function areArraysEqualUnordered(arr1, arr2) {
if (arr1.length !== arr2.length) return false;
const sortedArr1 = arr1.slice().sort();
const sortedArr2 = arr2.slice().sort();
return JSON.stringify(sortedArr1) === JSON.stringify(sortedArr2);
}
const isFold = computed(() => {
return !areArraysEqualUnordered(collapses, collapseActiveKey.value);
});
function handleFold() {
collapseActiveKey.value = isFold.value ? collapses : [];
}
/** Hooks - 表格 */
const gridOptions = reactive(gridProps({
minHeight: "300px",
columns: getColumns(),
data: [],
toolbarConfig: {
enabled: false,
},
pagerConfig: {
enabled: false,
},
rowConfig: {
useKey: true,
isCurrent: false,
},
})
);
const beforeUpload: UploadProps["beforeUpload"] = (file) => {
return false;
};
function handleBack() {
Modal.confirm({
title: "提示",
title: '提示',
content: `是否确认返回上一页面?`,
onOk: async () => {
back();
@ -94,81 +87,64 @@ function handleBack() {
* 页面返回并关闭tab
*/
function back() {
router.replace('/contract/approval/list')
}
function handleOpenSignBasisModal(row) {
router.replace('/contract/company/list');
}
let fileList = ref<UploadFile[]>([]);
const handleChange = (info: UploadChangeParam) => {
formRef.value.setFormData({
fileList.value = info.fileList.length ? info.fileList : [];
};
const handleChangeByCertification = (info: UploadChangeParam) => {
formRefByCertification.value.setFormData({
fileList: info.fileList.length ? info.fileList : [],
});
};
function removeRow(row) {
const $grid = xGridRef.value;
if ($grid) {
let hideLoading = message.loading("移除中")
Apis.addressor.post_deletes({ params: { ids: row['guid'] } }).then((data) => {
$grid.remove(row);
message.success('移除成功')
}).catch((err) => {
console.log(err)
message.error('移除失败,请稍候再试')
}).finally(() => {
hideLoading()
})
}
}
function handleDelete() {
Modal.confirm({
title: '提示',
content: "是否确认删除该条记录?",
content: '是否确认删除该条记录?',
okType: 'danger',
onOk: async () => {
await Apis.contractBaseInfo.post_deletes({ params: { ids: currData.value['guid'] } })
message.success("删除成功");
back()
await Apis.contractBaseInfo.post_deletes({
params: { ids: currData.value['guid'] },
});
message.success('删除成功');
back();
},
});
}
function loadDataByContractTypeData() {
}
function loadDataByContractTypeData() {}
async function handleSave() {
isLoading.value = true
isLoading.value = true;
try {
let form = formRef.value.form;
console.log(formRef.value)
console.log(formRef.value);
await formRef.value.submit()
await formRef.value.submit();
const userStore = useUserStore();
const userStore = useUserStore()
let newForm = {}
let newForm = {};
//
let fileList = formRef.value.form.fileList
let files: any = []
let fileList = formRef.value.form.fileList;
let files: any = [];
if (fileList && fileList.length) {
files = await fileUploader.upload(fileList, { source: 'ht' })
files = await fileUploader.upload(fileList, { source: 'ht' });
}
console.log(files)
console.log(files);
if (files) {
newForm.fileUuid = (files.map((item) => item.fileUuid) || []).join(',')
newForm.fileUuid = (files.map((item) => item.fileUuid) || []).join(',');
}
newForm = Object.assign({}, formRef.value.form, newForm)
newForm = Object.assign({}, formRef.value.form, newForm);
delete newForm.fileList
delete newForm.fileList;
// name
for (const item of contractTypeData.value) {
@ -182,26 +158,26 @@ async function handleSave() {
newForm.fundDitchName = getDictObj(
DICT_TYPE.contractFundingSource,
newForm.fundDitch
newForm.fundDitch,
)?.label;
newForm.priceTypeName = getDictObj(
DICT_TYPE.contractCurrencyUnit,
newForm.priceType
newForm.priceType,
)?.label;
newForm.contractMoney = newForm.budgetSum;
newForm.currentContStepId = 0;
console.log(newForm)
console.log(newForm);
await Apis.contractBaseInfo.post_apply({ data: newForm }).then((data) => {
message.success("保存成功");
message.success('保存成功');
Modal.confirm({
title: "提示",
content: "保存成功!是否进行提交?",
title: '提示',
content: '保存成功!是否进行提交?',
onOk: () => {
handleSubmit()
handleSubmit();
},
onCancel: () => {
back();
@ -209,159 +185,177 @@ async function handleSave() {
});
});
} catch (error) {
message.error("提交失败,请稍候再试");
console.log(error)
message.error('提交失败,请稍候再试');
console.log(error);
} finally {
isLoading.value = false
isLoading.value = false;
}
}
async function handleSubmit() {
try {
//
await Apis.contractBaseInfo.post_apply({ data: {} }).then((data) => {
message.success("提交成功");
message.success('提交成功');
back();
});
} catch (error) {
message.error("提交失败,请稍候再试");
console.log(error)
message.error('提交失败,请稍候再试');
console.log(error);
} finally {
isLoading.value = false
isLoading.value = false;
}
}
const currData = ref({})
const currData = ref({});
onMounted(async () => {
isLoading.value = true
console.log(id)
isLoading.value = true;
console.log(id);
// let formSchema = getFormSchema()
// formBinding.value = formSchema
try {
let contractReferTypeData = await Apis.contractReferType.get_list({ params: {} })
contractTypeData.value = contractReferTypeData.rows || [];
formBinding.value.columns = getFormSchema({
contractTypeData: contractTypeData.value
})
if (id) {
let data = await Apis.contractBaseInfo.get_getOne({ params: { guid: id } })
console.log(data)
let data = await Apis.contractBaseInfo.get_getOne({
params: { guid: id },
});
console.log(data);
currData.value = data;
nextTick(() => {
formRef.value.setFormData(data)
})
formRef.value.setFormData(data);
});
if (data.fileUuid) {
let files = await fileUploader.select(data.fileUuid)
console.log(files)
let files = await fileUploader.select(data.fileUuid);
console.log(files);
nextTick(() => {
formRef.value.setFormData({
fileList: files
})
})
fileList: files,
});
});
}
loadDataByContractTypeData()
loadDataByContractTypeData();
}
} catch (error) {
console.log(error);
Modal.error({
title: "提示",
content: "当前合同信息不存在",
title: '提示',
content: '当前合同信息不存在',
onOk() {
back();
},
});
} finally {
isLoading.value = false
isLoading.value = false;
}
})
});
</script>
<template>
<Page id="components-affix-demo-target" ref="containerRef" contentClass="h-full flex flex-col overflow-y-scroll">
<Page ref="pageRef" contentClass="h-full flex flex-col">
<a-affix
:target="() => pageRef.bodyRef"
:offset-top="0"
:style="{ zIndex: 50 }"
>
<div class="flex w-full flex-row bg-white pl-1 pt-1">
<a-space class="flex-1">
<vben-button variant="primary" @click="handleSave()"
>保存</vben-button
>
<vben-button v-if="id" variant="destructive" @click="handleDelete()">
删除
</vben-button>
<vben-button variant="secondary" @click="handleBack()"
>返回</vben-button
>
</a-space>
<vben-button variant="secondary" @click="handleFold()"
>一键{{ isFold ? '展开' : '收起' }}</vben-button
>
</div>
</a-affix>
<a-spin :spinning="isLoading">
<a-space>
<vben-button variant="primary" @click="handleSave()">保存</vben-button>
<vben-button variant="primary" @click="handleSubmit()">提交</vben-button>
<vben-button v-if="id" variant="destructive" @click="handleDelete()">
删除
</vben-button>
<vben-button variant="secondary" @click="handleBack()">返回</vben-button>
</a-space>
<div class="mx-auto w-[800px] overflow-auto">
<a-space direction="vertical">
<a-card title="基本信息" size="small" class="w-full">
<div class="mx-auto overflow-auto py-2">
<a-collapse v-model:activeKey="collapseActiveKey" :bordered="false">
<a-collapse-panel key="1" header="基本信息" class="w-full">
<fs-form ref="formRef" class="w-full" v-bind="formBinding">
</fs-form>
</a-collapse-panel>
<a-collapse-panel key="2" header="银行开户信息" class="w-full">
<fs-form
ref="formRefByBank"
class="w-full"
v-bind="formBindingByBank"
>
</fs-form>
</a-collapse-panel>
<a-collapse-panel key="3" header="资质信息" class="w-full">
<fs-form
ref="formRefByCertification"
class="w-full"
v-bind="formBindingByCertification"
>
<template #form_fileList="scope">
<a-upload v-model:fileList="scope.form.fileList" accept=".pdf,.ppt,.pptx" :max-count="3" name="file"
:before-upload="beforeUpload" @change="handleChange">
<a-upload
v-model:fileList="scope.form.fileList"
accept=".pdf"
:max-count="3"
name="file"
:before-upload="() => false"
@change="handleChangeByCertification"
>
<vben-button variant="secondary">
<MdiUpload />
点击上传
</vben-button>
</a-upload>
</template>
</fs-form>
</a-collapse-panel>
<a-collapse-panel key="4" header="股东信息" class="w-full">
<fs-form
ref="formRefByShareholder"
class="w-full"
v-bind="formBindingByShareholder"
>
</fs-form>
</a-collapse-panel>
<a-collapse-panel key="5" header="合同相对人附件" class="w-full">
<a-form :label-col="{ style: { width: '120px' } }">
<a-form-item name="fileList" label="附件上传">
<a-upload
v-model:fileList="fileList"
accept=".pdf,.ppt,.pptx"
:max-count="3"
name="file"
:before-upload="() => false"
@change="handleChange"
>
<a-button>
<MdiUpload />
点击上传
</a-button>
</a-upload>
</template>
</fs-form>
</a-card>
<a-card title="签约依据" size="small" class="w-[800px]">
<template #extra>
<a-button size="small" type="primary" @click="handleOpenSignBasisModal()">
<MdiAdd class="text-lg mr-0.5" />
选择签约依据
</a-button>
</template>
<VxeGrid ref="xGridRef" v-bind="gridOptions" class="w-[800px]">
<template #toolbar_buttons></template>
<template #operate="{ row }">
<a-space>
<a-button type="text" class="text-yellow-500" size="small" @click="handleOpenSignBasisModal(row)">
编辑
</a-button type="text">
<a-button type="text" class="text-red-500" size="small" @click="removeRow(row)">
移除
</a-button type="text">
</a-space>
</template>
</VxeGrid>
</a-card>
</a-space>
</a-form-item>
</a-form>
</a-collapse-panel>
</a-collapse>
</div>
</a-spin>
</Page>
</template>
<style scoped>
.sortable-tree-demo .drag-btn {
cursor: move;
font-size: 12px;
text-align: center;
}
.sortable-tree-demo .vxe-body--row.sortable-ghost,
.sortable-tree-demo .vxe-body--row.sortable-chosen {
background-color: #dfecfb;
}
</style>
<style scoped></style>

View File

@ -8,12 +8,21 @@ export const PrimaryKey = 'guid';
export function getColumns(params: any = {}): VxeGridPropTypes.Columns {
return [
{ type: 'radio', width: 40, slots: { radio: 'radio_cell' }, align: 'center', fixed: 'left' },
{
type: 'radio',
width: 40,
slots: { radio: 'radio_cell' },
align: 'center',
fixed: 'left',
},
{ field: 'providerId', title: '编号', width: 100 },
{
field: 'providerName', title: '相对人名称', minWidth: 200, slots: {
default: 'provider-name-slot'
}
field: 'providerName',
title: '相对人名称',
minWidth: 200,
slots: {
default: 'provider-name-slot',
},
},
{ field: 'providerKindName', title: '性质', width: 150 },
{ field: 'fundDitchName', title: '住所', width: 150 },
@ -25,7 +34,7 @@ export function getColumns(params: any = {}): VxeGridPropTypes.Columns {
{ field: 'createPerson', title: '创建人', width: 100 },
{ field: 'createDate', title: '创建时间', width: 100 },
{ field: 'inputDepartName', title: '备注', width: 100 },
]
];
}
export function getFormSchema(_params: any = {}) {
@ -43,6 +52,51 @@ export function getFormSchema(_params: any = {}) {
autoSearchTrigger: 'enter',
show: true,
},
juridicalPerson: {
title: '法人姓名',
key: 'juridicalPerson',
component: {
name: 'a-input',
vModel: 'value',
allowClear: true,
},
autoSearchTrigger: 'enter',
show: true,
},
currencyTypeId: {
title: '币种',
key: 'currencyTypeId',
component: {
name: 'fs-dict-select',
vModel: 'value',
dict: dict({
data: getDictOptions(DICT_TYPE.contractCurrencyUnit),
}),
},
show: true,
},
organizeNum: {
title: '组织机构代码',
key: 'organizeNum',
component: {
name: 'a-input',
vModel: 'value',
allowClear: true,
},
autoSearchTrigger: 'enter',
show: true,
},
creditCode: {
title: '统一社会信用代码',
key: 'creditCode',
component: {
name: 'a-input',
vModel: 'value',
allowClear: true,
},
autoSearchTrigger: 'enter',
show: true,
},
},
};
}

View File

@ -0,0 +1,214 @@
import { DICT_TYPE, getDictOptions } from '#/utils/dict';
import { dict } from '@fast-crud/fast-crud';
import { render } from 'vue';
/**
*
*
*/
function filterContractTypes(contractTypeData: any = [], parentId: string) {
return contractTypeData
.map((item) => {
item.label = item.contrLevelName;
item.value = item.contrLevelId;
return item;
})
.filter((item) => item.parentId === parentId);
}
export function getFormSchema(params: any = {}) {
const { contractTypeData } = params;
return {
contractName: {
title: '合同名称',
key: 'contractName',
col: { span: 16 },
component: {
name: 'a-input',
vModel: 'value',
allowClear: false,
},
conditionalRender: {
match({ form }) {
return true;
},
render({ form }) {
return <span>{form.contractName}</span>;
},
},
},
reportNo: {
title: '报审序号',
key: 'reportNo',
col: { span: 8 },
component: {
name: 'a-input',
vModel: 'value',
allowClear: false,
},
conditionalRender: {
match({ form }) {
return true;
},
render({ form }) {
return <span>{form.reportNo}</span>;
},
},
},
ctrType: {
title: '合同类别',
key: 'ctrType',
col: { span: 8 },
component: {
name: 'fs-dict-select',
vModel: 'value',
class: 'min-w-[200px]',
dict: dict({
async getData({ form = {}, getComponentRef }) {
return filterContractTypes(contractTypeData, '-1');
},
}),
},
conditionalRender: {
match({ form }) {
return true;
},
render({ form }) {
return <span>{form.reportNo}</span>;
},
},
},
ctrTwoType: {
title: '二级类别',
key: 'ctrTwoType',
col: { span: 8 },
component: {
name: 'fs-dict-select',
vModel: 'value',
class: 'min-w-[200px]',
dict: dict({
async getData({ form = {} }) {
if (form.ctrType) {
return filterContractTypes(contractTypeData, form.ctrType);
}
return contractTypeData;
},
}),
},
rules: [{ required: true }],
},
ctrThreeType: {
title: '三级类别',
key: 'ctrTwoType',
col: { span: 8 },
render({ form }) {
return <span></span>;
},
},
budgetSum: {
title: '预算金额',
key: 'budgetSum',
col: { span: 5 },
colon: false,
component: {
name: 'a-input-number',
vModel: 'value',
class: 'w-full',
min: 0,
max: 9999,
},
},
priceType: {
title: '',
key: 'priceType',
col: { span: 3 },
labelCol: { style: { width: '12px' } },
colon: false,
component: {
name: 'fs-dict-select',
vModel: 'value',
dict: dict({
data: getDictOptions(DICT_TYPE.contractCurrencyUnit),
}),
},
},
fundAllocation: {
title: '资金流向',
key: 'fundAllocation',
col: { span: 8 },
component: {
name: 'fs-dict-select',
vModel: 'value',
allowClear: false,
class: 'min-w-[200px]',
dict: dict({
data: getDictOptions(DICT_TYPE.contractFundFlow),
}),
},
rules: [{ required: true, message: '请选择资金流向' }],
},
fundDitch: {
title: '资金渠道',
key: 'fundDitch',
col: { span: 8 },
component: {
name: 'fs-dict-select',
vModel: 'value',
allowClear: false,
class: 'min-w-[200px]',
dict: dict({
data: getDictOptions(DICT_TYPE.contractFundingSource),
}),
},
rules: [{ required: true, message: '请选择资金渠道' }],
},
frameProtocol: {
title: '框架协议',
key: 'frameProtocol',
col: { span: 8 },
component: {
name: 'fs-dict-radio',
vModel: 'value',
dict: dict({
data: [
{ label: '是', value: 1 },
{ label: '否', value: 0 },
],
}),
},
},
frameProtocolCtr: {
title: '框架协议下的合同',
key: 'frameProtocolCtr',
col: { span: 8 },
labelCol: { style: { width: '150px' } },
component: {
name: 'fs-dict-radio',
vModel: 'value',
dict: dict({
data: [
{ label: '是', value: 1 },
{ label: '否', value: 0 },
],
}),
},
},
organiza: {
title: '组织方式',
key: 'organiza',
col: { span: 8 },
component: {
name: 'fs-dict-radio',
vModel: 'value',
allowClear: false,
class: 'min-w-[200px]',
dict: dict({
data: getDictOptions(DICT_TYPE.contractOrganizationForm),
}),
},
rules: [{ required: true, message: '请选择组织方式' }],
},
};
}

View File

@ -0,0 +1,177 @@
import { DICT_TYPE, getDictOptions } from "#/utils/dict";
import { dict } from "@fast-crud/fast-crud";
export function getFormSchema(_params: any = {}) {
return {
projectNum: {
title: "项目",
key: "projectNum",
col: { span: 12 },
component: {
name: "a-input",
vModel: "value",
allowClear: false,
},
rules: [{ required: true }],
},
projectProp: {
title: "项目类别",
key: "projectProp",
col: { span: 12 },
component: {
name: "fs-dict-radio",
vModel: "value",
class: 'min-w-[200px]',
dict: dict({
data: getDictOptions(DICT_TYPE.contractProjectType)
}),
},
rules: [{ required: true }],
},
projectName: {
title: "项目名称",
key: "projectName",
col: { span: 24 },
component: {
name: "fs-dict-select",
vModel: "value",
class: 'min-w-[200px]',
dict: dict({
data: getDictOptions(DICT_TYPE.comprehensiveProjectName)
}),
},
rules: [{ required: true }],
},
priceStyleId: {
title: "商务计价方式",
key: "priceStyleId",
col: { span: 24 },
component: {
name: "fs-dict-radio",
vModel: "value",
class: 'min-w-[200px]',
dict: dict({
data: getDictOptions(DICT_TYPE.contractPriceStyle)
}),
},
},
choiceType: {
title: "选商方式",
key: "choiceType",
col: { span: 24 },
component: {
name: "fs-dict-radio",
vModel: "value",
dict: dict({
data: getDictOptions(DICT_TYPE.contractSelectionMethod)
}),
},
},
choiceReason: {
title: "选商方式说明",
key: "choiceReason",
col: { span: 24 },
component: {
name: "a-textarea",
vModel: "value",
autosize: { minRows: 4, maxRows: 6 }
},
},
qualificReq: {
title: "资质要求",
key: "qualificReq",
col: { span: 24 },
component: {
name: "a-textarea",
vModel: "value",
autosize: { minRows: 4, maxRows: 6 }
},
},
isBid: {
title: "划分标段",
key: "isBid",
col: { span: 24 },
// component: {
// name: "fs-dict-radio",
// vModel: "value",
// dict: dict({
// data: getDictOptions(DICT_TYPE.sectionType)
// }),
// },
render({ form }) {
//注意此处的v-model写法
let options1 = getDictOptions(DICT_TYPE.sectionType,'string')
let options2 = getDictOptions(DICT_TYPE.sectionNum,'string')
return (
<div class="flex">
<a-form-item class="inline-block !mb-0">
<a-radio-group v-model:value={form.isBid} options={options1} />
</a-form-item>
<div class="w-2"></div>
{form.isBid === 1 && (
<a-form-item label="标段数" class="inline-block !mb-0">
<a-radio-group v-model:value={form.budgetSum2} options={options2} />
</a-form-item>
)}
</div>
);
}
},
projectRange: {
title: "项目范围",
key: "projectRange",
col: { span: 24 },
component: {
name: "a-textarea",
vModel: "value",
autosize: { minRows: 4, maxRows: 6 }
},
},
projectContent: {
title: "项目内容",
key: "projectContent",
col: { span: 24 },
component: {
name: "a-textarea",
vModel: "value",
autosize: { minRows: 4, maxRows: 6 }
},
},
quality: {
title: "工期/质量要求",
key: "quality",
col: { span: 24 },
labelWrap:true,
component: {
name: "a-textarea",
vModel: "value",
autosize: { minRows: 4, maxRows: 6 }
},
},
stockNums: {
title: "工程/采购量",
key: "stockNums",
col: { span: 24 },
labelWrap:true,
component: {
name: "a-textarea",
vModel: "value",
autosize: { minRows: 4, maxRows: 6 }
},
},
stockPlanMx: {
title: "计划投资明细",
key: "stockPlanMx",
col: { span: 24 },
labelWrap:true,
component: {
name: "a-textarea",
vModel: "value",
autosize: { minRows: 4, maxRows: 6 }
},
},
}
}

View File

@ -0,0 +1,447 @@
<script setup lang="ts">
import { ref, computed, reactive, onMounted, nextTick, onUnmounted } from "vue";
import { MdiAdd } from '@vben/icons';
import { Page, useVbenModal } from "@vben/common-ui";
import { MdiUpload } from "@vben/icons";
import { useRouter } from 'vue-router'
import dayjs, { Dayjs } from "dayjs";
import Apis from "#/api";
import { message, Modal, type UploadChangeParam, type UploadFile, type UploadProps } from 'ant-design-vue';
import { useUserStore } from "@vben/stores";
import { useRoute } from "vue-router";
import { getFormSchema } from "./curd";
import { getFormSchema as getFormSchemaByBaseInfo } from "./basic-info-curd";
import { FileUploader } from "#/utils/file";
import { DICT_TYPE, getDictObj, getDictOptions } from "#/utils/dict";
import { useVxeTable } from "#/hooks/vxeTable";
const { xGridRef, gridProps, triggerProxy } = useVxeTable({ ref: "xGridRef" });
const fileUploader = new FileUploader({})
const router = useRouter();
const route = useRoute();
const id = route.params.id;
const pageRef = ref();
let showHelpTip = ref(false);
const containerRef = ref();
const formRef = ref();
const formRefByBaseInfo = ref();
let isLoading = ref(false)
let contractTypeData = ref(['1'])
const formBindingByBaseInfo = ref({
col: { span: 24 },
initialForm: {},
labelCol: { style: { width: "120px" } },
columns: {}
});
const formBinding = ref({
col: { span: 24 },
initialForm: {
contractName: '',
priceType: 'CNY',
isBid: '0'
},
labelCol: { style: { width: "120px" } },
columns: getFormSchema()
});
function getColumns(): any {
return [
{ type: "seq", title: "序号", width: 60 },
{ field: "referenceName", title: "签约依据名称", minWidth: 150 },
{ field: "referenceId", title: "签约依据编号", width: 200 },
{ field: "attachments", title: "附件", width: 120 },
{
title: "操作",
width: 120,
slots: { default: "operation" },
},
];
}
/** Hooks - 表格 */
const gridOptions = reactive(gridProps({
height: "200px",
columns: getColumns(),
data: [],
toolbarConfig: {
enabled: false,
},
pagerConfig: {
enabled: false,
},
rowConfig: {
useKey: true,
isCurrent: false,
},
})
);
let fileList = ref<UploadFile[]>([])
const beforeUpload: UploadProps["beforeUpload"] = (file) => {
return false;
};
function handleBack() {
Modal.confirm({
title: "提示",
content: `是否确认返回上一页面?`,
onOk: async () => {
back();
},
});
}
/**
* 页面返回并关闭tab
*/
function back() {
router.replace('/contract/declaration/list')
}
const handleChange = (info: UploadChangeParam) => {
fileList.value = info.fileList.length ? info.fileList : []
};
function handleDelete() {
Modal.confirm({
title: '提示',
content: "是否确认删除该条记录?",
okType: 'danger',
onOk: async () => {
await Apis.contractBaseInfo.post_deletes({ params: { ids: currData.value['guid'] } })
message.success("删除成功");
back()
},
});
}
let collapses = ['1', '2', '3', '4']
let collapseActiveKey = ref(collapses)
function areArraysEqualUnordered(arr1, arr2) {
if (arr1.length !== arr2.length) return false;
const sortedArr1 = arr1.slice().sort();
const sortedArr2 = arr2.slice().sort();
return JSON.stringify(sortedArr1) === JSON.stringify(sortedArr2);
}
const isFold = computed(() => {
return !areArraysEqualUnordered(collapses, collapseActiveKey.value)
})
function handleFold() {
collapseActiveKey.value = isFold.value ? collapses : []
}
function loadDataByContractTypeData() {
}
async function handleSave() {
isLoading.value = true
try {
console.log(formRef.value)
await formRef.value.submit()
await formRefByBaseInfo.value.submit()
let contractForm = formRefByBaseInfo.value.form;
let bussinessForm = formRef.value.form;
bussinessForm.priceStyleName = getDictObj(DICT_TYPE.contractPriceStyle, bussinessForm.priceStyleId)?.label
bussinessForm.choiceTypeName = getDictObj(DICT_TYPE.contractSelectionMethod, bussinessForm.choiceType)?.label;
//
{
let tempFileList = contractForm.fileList
let tempFiles: any = []
if (fileList && tempFileList.length) {
tempFiles = await fileUploader.upload(tempFileList, { source: 'ht' })
}
console.log(tempFiles)
if (tempFiles) {
contractForm.fileUuid = (tempFiles.map((item) => item.fileUuid) || []).join(',')
}
}
//
{
let tempFileList = fileList.value
let tempFiles: any = []
if (fileList && tempFileList.length) {
tempFiles = await fileUploader.upload(tempFileList, { source: 'ht' })
}
console.log(tempFiles)
if (tempFiles) {
bussinessForm.fileUuid = (tempFiles.map((item) => item.fileUuid) || []).join(',')
}
}
let form = {
contractBaseInfo: contractForm,
selectMerchantsBasicInfo: bussinessForm,
biddingList: xGridRef.value?.getTableData().fullData,
};
if (form.selectMerchantsBasicInfo.isBid) {
let biddingList: any[] = xGridRef.value?.getTableData().fullData || [];
let index = 1;
for (const item of biddingList) {
if (!item.phaseName) {
message.error(`标段信息中的标段名称不能为空`);
return;
}
if (!item.phaseMoney) {
message.error(`标段信息中的预算金额不能为空`);
return;
}
if (!item.phaseDesc) {
message.error(`标段信息中的标段范围说明不能为空`);
return;
}
item.phaseSeq = index + "";
index++;
}
form.biddingList = biddingList;
}
console.log("提交表单", form)
return
const userStore = useUserStore()
let newForm = {}
//
// let fileList = formRef.value.form.fileList
// let files: any = []
// if (fileList && fileList.length) {
// files = await fileUploader.upload(fileList, { source: 'ht' })
// }
// console.log(files)
// if (files) {
// newForm.fileUuid = (files.map((item) => item.fileUuid) || []).join(',')
// }
newForm = Object.assign({}, formRef.value.form, newForm)
delete newForm.fileList
// name
for (const item of contractTypeData.value) {
if (item.contrLevelId == newForm.ctrType) {
newForm.ctrTypeName = item.contrLevelName;
}
if (item.contrLevelId == newForm.ctrTwoType) {
newForm.ctrTwoTypeName = item.contrLevelName;
}
}
newForm.fundDitchName = getDictObj(
DICT_TYPE.contractFundingSource,
newForm.fundDitch
)?.label;
newForm.priceTypeName = getDictObj(
DICT_TYPE.contractCurrencyUnit,
newForm.priceType
)?.label;
newForm.contractMoney = newForm.budgetSum;
newForm.currentContStepId = 0;
console.log(newForm)
await Apis.contractBaseInfo.post_apply({ data: newForm }).then((data) => {
message.success("保存成功");
Modal.confirm({
title: "提示",
content: "保存成功!是否进行提交?",
onOk: () => {
handleSubmit()
},
onCancel: () => {
back();
},
});
});
} catch (error) {
message.error("提交失败,请稍候再试");
console.log(error)
} finally {
isLoading.value = false
}
}
async function handleSubmit() {
try {
await Apis.contractBaseInfo.post_apply({ data: {} }).then((data) => {
message.success("提交成功");
back();
});
} catch (error) {
message.error("提交失败,请稍候再试");
console.log(error)
} finally {
isLoading.value = false
}
}
let contractData = ref<any>({})
let businessData = ref<any>({})
const currData = ref({})
onMounted(async () => {
isLoading.value = true
console.log(id)
try {
if (id) {
let contractReferTypeData = await Apis.contractReferType.get_list({ params: {} })
contractTypeData.value = contractReferTypeData.rows || [];
formBindingByBaseInfo.value.columns = getFormSchemaByBaseInfo({
contractTypeData: contractTypeData.value
})
//
let contract: any = await Apis.contractBaseInfo.get_getOne({ params: { contractId: id } })
if (contract && contract.contractId) {
contractData.value = contract
let business: any = await Apis.selectMerchantsBasicInfo.get_getOne({ params: { contractId: contract.contractId } })
console.log(business)
if (business.fileUuid) {
let files = await fileUploader.select(business.fileUuid)
business.fileList = files
}
businessData.value = business
nextTick(() => {
formRefByBaseInfo.value.setFormData(contract)
formRef.value.setFormData(business)
})
} else {
throw new Error("当前合同信息不存在")
}
loadDataByContractTypeData()
} else {
throw new Error("当前合同信息不存在")
}
} catch (error) {
console.log(error);
Modal.error({
title: "提示",
content: "当前合同信息不存在",
onOk() {
back();
},
});
} finally {
isLoading.value = false
}
})
</script>
<template>
<Page ref="pageRef" contentClass="h-full flex flex-col">
<a-affix :target="() => pageRef.bodyRef" :offset-top="0" :style="{ zIndex: 50 }">
<div class="bg-white w-full flex flex-row pt-1 pl-1">
<a-space class="flex-1">
<vben-button variant="primary" @click="handleSave()">保存</vben-button>
<vben-button variant="primary" @click="handleSubmit()">提交</vben-button>
<vben-button variant="destructive" @click="handleDelete()">
废除
</vben-button>
<vben-button variant="secondary" @click="handleBack()">返回</vben-button>
</a-space>
<vben-button variant="secondary" @click="handleFold()">一键{{ isFold ? '展开' : '收起' }}</vben-button>
</div>
</a-affix>
<a-spin :spinning="isLoading">
<div class="mx-auto overflow-auto py-2">
<a-collapse v-model:activeKey="collapseActiveKey" :bordered="false">
<a-collapse-panel key="1" header="基本信息" class="w-full">
<fs-form ref="formRefByBaseInfo" class="w-full" v-bind="formBindingByBaseInfo">
<template #form_fileList="scope">
<a-upload v-model:fileList="scope.form.fileList" accept=".pdf,.ppt,.pptx" :max-count="3" name="file"
:before-upload="beforeUpload" @change="handleChange">
<a-button>
<MdiUpload />
点击上传
</a-button>
</a-upload>
</template>
</fs-form>
</a-collapse-panel>
<a-collapse-panel key="2" header="签约依据" class="w-full">
<VxeGrid ref="xGridRef" v-bind="gridOptions" class="">
<template #toolbar_buttons></template>
</VxeGrid>
</a-collapse-panel>
<a-collapse-panel key="3" header="选商资料" class="w-full">
<fs-form ref="formRef" class="w-full" v-bind="formBinding">
</fs-form>
</a-collapse-panel>
<a-collapse-panel key="4" header="招标文件上传" class="w-full">
<a-form :label-col="{ style: { width: '120px' } }">
<a-form-item name="fileList" label="附件上传">
<a-upload v-model:fileList="fileList" accept=".pdf,.ppt,.pptx" :max-count="3" name="file"
:before-upload="beforeUpload" @change="handleChange">
<a-button>
<MdiUpload />
点击上传
</a-button>
</a-upload>
</a-form-item>
</a-form>
</a-collapse-panel>
</a-collapse>
</div>
</a-spin>
</Page>
</template>
<style scoped>
.sortable-tree-demo .drag-btn {
font-size: 12px;
text-align: center;
cursor: move;
}
.sortable-tree-demo .vxe-body--row.sortable-ghost,
.sortable-tree-demo .vxe-body--row.sortable-chosen {
background-color: #dfecfb;
}
</style>

View File

@ -18,17 +18,16 @@ export function getColumns(params: any = {}): VxeGridPropTypes.Columns {
},
{ field: 'contractSubject', title: '合同标的', width: 150 },
{
field: 'objectsSum', title: '标的金额', width: 100, slots: {
field: 'objectsSum', title: '标的金额', width: 150, slots: {
default: ({ row }) => {
return useRender.renderText(row.objectsSum, row.priceTypeName);
}
}
},
{ field: 'contractHandler', title: '合同承办人', width: 120 },
{ field: 'counterpartyName', title: '合同相对人名称', width: 150 },
{ field: 'contractSource', title: '合同来源', width: 100 },
{ field: 'procurementMethod', title: '采购方式', width: 120 },
{ field: 'inputPerson', title: '承办人', width: 120 },
{ field: 'inputPerson', title: '合同承办人', width: 120 },
{ field: 'providerName', title: '合同相对人名称', width: 150 },
{ field: 'contractSourceType', title: '合同来源', width: 100 },
{ field: 'choiceTypeName', title: '采购方式', width: 120 },
{ field: 'inputDeptName', title: '承办人部门', width: 120 },
{ field: 'inputDate', title: '承办时间', width: 150 }
]
@ -37,7 +36,6 @@ export function getColumns(params: any = {}): VxeGridPropTypes.Columns {
export function getFormSchema(_params: any = {}) {
return {
initialForm: {
startDate: dayjs().startOf('month').format("YYYY-MM-DD"),
},
columns: {
contractName: {

View File

@ -2,114 +2,114 @@
import { ref, computed, reactive, onMounted } from 'vue';
import { Page, useVbenModal } from '@vben/common-ui';
import { useVxeTable } from '#/hooks/vxeTable';
import { MdiAdd, MdiUpdate, MdiDelete, MdiImport, MdiExport, MdiRadioUnchecked, MdiRadioChecked } from '@vben/icons';
import {
MdiAdd,
MdiUpdate,
MdiDelete,
MdiImport,
MdiExport,
MdiRadioUnchecked,
MdiRadioChecked,
} from '@vben/icons';
import { getFormSchema, getColumns, PrimaryKey } from './crud.tsx';
import { getMonthStartAndEnd } from '#/utils/time'
import Apis from '#/api'
import { getMonthStartAndEnd } from '#/utils/time';
import Apis from '#/api';
import dayjs from 'dayjs';
import { message } from "ant-design-vue";
import { message } from 'ant-design-vue';
import { Modal } from 'ant-design-vue';
import { useRouter } from 'vue-router'
import { useRouter } from 'vue-router';
const router = useRouter();
const checkedValue = ref('all')
const checkedValue = ref('all');
const exportSearchParams = ref<any>({
daterange: getMonthStartAndEnd(),
});
const searchRef = ref()
let isConfirmLoading = ref(false)
const searchRef = ref();
let isConfirmLoading = ref(false);
const [_Modal, modalApi] = useVbenModal({
async onConfirm() {
isConfirmLoading.value = true
isConfirmLoading.value = true;
try {
let params = {};
if (checkedValue.value == "daterange") {
if (checkedValue.value == 'daterange') {
params = {
startDate: exportSearchParams.value.daterange[0],
endDate: exportSearchParams.value.daterange[1],
};
}
let res = await Apis.zbgl.post_export({
params: params, config: {
meta: {
responseType: 'blob'
}
}
}).send();
message.success("导出成功");
modalApi.close()
let res = await Apis.zbgl
.post_export({
params: params,
config: {
meta: {
responseType: 'blob',
},
},
})
.send();
message.success('导出成功');
modalApi.close();
showExportModal.value = false;
} catch (error) {
console.error(error);
} finally {
isConfirmLoading.value = false
isConfirmLoading.value = false;
}
console.info("onConfirm");
console.info('onConfirm');
},
});
const { xGridRef, triggerProxy, gridProps } = useVxeTable({ ref: 'xGridRef' });
const treeData = ref([]);
/** Hooks - 表格 */
const gridOptions = reactive(gridProps({
columns: getColumns(),
proxyConfig: {
autoLoad: false,
ajax: {
query: ({ page }) => {
return Apis.contractBaseInfo.get_page({ params: { pageNum: page.currentPage, pageSize: page.pageSize, ...searchRef.value?.formData } })
}
const gridOptions = reactive(
gridProps({
columns: getColumns(),
proxyConfig: {
autoLoad: false,
ajax: {
query: ({ page }) => {
return Apis.sbCtrBasePt.get_QuerySbCtrBase({
params: {
pageNum: page.currentPage,
pageSize: page.pageSize,
...searchRef.value?.formData,
},
});
},
},
},
},
pagerConfig: {
enabled: true
},
toolbarConfig: {
enabled: true
},
}));
pagerConfig: {
enabled: true,
},
toolbarConfig: {
enabled: true,
},
}),
);
function handleEdit(record?: any) {
if (record && record[PrimaryKey]) {
router.push("/contract/approval/edit/" + record[PrimaryKey]);
router.push('/contract/declaration/edit/' + record['ctrBaseId']);
} else {
router.push("/contract/approval/edit");
router.push('/contract/declaration/edit');
}
}
function handleDelete(row) {
Modal.confirm({
title: '提示',
content: "是否确认删除该条记录?",
okType: 'danger',
onOk: async () => {
await Apis.contractBaseInfo.post_deletes({ params: { ids: row[PrimaryKey] } })
message.success("删除成功");
triggerProxy("reload");
},
onCancel() {
console.log('Cancel');
},
});
}
function handleExport() {
const $grid = xGridRef.value;
if ($grid) {
$grid.exportData({
type: "xlsx",
type: 'xlsx',
});
message.success("导出成功");
message.success('导出成功');
}
}
@ -133,25 +133,15 @@ function handleCellClick({ row }) {
}
onMounted(() => {
triggerProxy('reload')
})
triggerProxy('reload');
});
const searchForm = ref({
...getFormSchema(),
onSearch(context: any) {
triggerProxy('reload')
}
triggerProxy('reload');
},
});
function toPage() {
window.open("/iframe/meeting/standing-book", "_blank");
}
function toDetail(row) {
window.open("/iframe/meeting/start/" + row.guid, "_blank");
}
//
</script>
<template>
@ -165,36 +155,44 @@ function toDetail(row) {
</a-input-number>
</template>
<template #form_time="{ row }">
<a-date-picker v-model:value="row.startTime" placeholder="" format="YYYY-MM-DD" value-format="YYYY-MM-DD">
<a-date-picker
v-model:value="row.startTime"
placeholder=""
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
>
</a-date-picker>
<span class="mx-1"></span>
<a-date-picker v-model:value="row.endTime" placeholder="" format="YYYY-MM-DD" value-format="YYYY-MM-DD">
<a-date-picker
v-model:value="row.endTime"
placeholder=""
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
>
</a-date-picker>
</template>
</fs-search>
<div class="flex-1 min-h-300px">
<vxe-grid ref="xGridRef" v-bind="gridOptions" @cell-click="handleCellClick">
<div class="min-h-300px flex-1">
<vxe-grid
ref="xGridRef"
v-bind="gridOptions"
@cell-click="handleCellClick"
>
<template #toolbar_buttons>
<a-space>
<vben-button variant="primary" @click="handleEdit()">
<MdiAdd class="text-lg mr-0.5" />
新增
</vben-button>
<vben-button variant="warning" :disabled="!selectRow || !selectRow[PrimaryKey]"
@click="handleEdit(selectRow)">
<MdiUpdate class="text-lg mr-0.5" />
<vben-button
variant="warning"
:disabled="!selectRow || !selectRow[PrimaryKey]"
@click="handleEdit(selectRow)"
>
<MdiUpdate class="mr-0.5 text-lg" />
修改
</vben-button>
<vben-button variant="primary" @click="handleExport()">
<MdiExport class="text-lg mr-0.5" />
<MdiExport class="mr-0.5 text-lg" />
导出
</vben-button>
<vben-button variant="destructive" :disabled="!selectRow || !selectRow[PrimaryKey]"
@click="handleDelete(selectRow)">
<MdiDelete class="text-lg mr-0.5" />
删除
</vben-button>
</a-space>
</template>
@ -205,6 +203,14 @@ function toDetail(row) {
</span>
</template>
<template #contract-name-slot="{ row }">
<span
class="text-blue cursor-pointer hover:underline"
@click="toDetail(row)"
>
{{ row.ctrName }}
</span>
</template>
</vxe-grid>
</div>
</Page>

View File

@ -15,7 +15,7 @@ export function getColumns(_params: any = {}): VxeGridPropTypes.Columns {
align: 'center',
slots: {
default: ({ row }) => {
return useRender.renderDate(row.dutyDate, 'YYYY年MMDD日');
return useRender.renderDate(row.dutyDate, 'YYYY年M月D日');
},
},
},

View File

@ -1,27 +1,38 @@
<template>
<div class="mx-auto h-screen flex flex-col px-8 bg-gray-100">
<p class="text-3xl font-bold my-6 text-center text-gray-800">
值班信息栏
</p>
<div class="mx-auto flex h-screen flex-col bg-gray-100 px-8">
<p class="my-6 text-center text-3xl font-bold text-gray-800">值班信息栏</p>
<div class="flex justify-center items-center mb-6">
<button @click="prevMonth" class="bg-primary text-white px-4 py-2 rounded-l-lg hover:bg-primary/90">
<div class="mb-6 flex items-center justify-center">
<button
@click="prevMonth"
class="bg-primary hover:bg-primary/90 rounded-l-lg px-4 py-2 text-white"
>
上一月
</button>
<span class="text-xl font-semibold mx-4">{{ currentMonth }}</span>
<button @click="nextMonth" class="bg-primary text-white px-4 py-2 rounded-l-lg hover:bg-primary/90">
<span class="mx-4 text-xl font-semibold">{{ currentMonth }}</span>
<button
@click="nextMonth"
class="bg-primary hover:bg-primary/90 rounded-l-lg px-4 py-2 text-white"
>
下一月
</button>
</div>
<div class="flex-1 bg-white rounded-lg shadow-md p-6 mb-8">
<vxe-grid ref="xGridRef" v-bind="gridOptions" @cell-click="handleCellClick">
<div class="mb-8 flex-1 rounded-lg bg-white p-4 shadow-md">
<vxe-grid
ref="xGridRef"
v-bind="gridOptions"
@cell-click="handleCellClick"
>
<template #toolbar_buttons>
<!-- 可添加工具栏按钮 -->
</template>
<template #radio_cell="{ row, checked }">
<span class="text-base cursor-pointer" @click.stop="setSelectRow(row)">
<span
class="cursor-pointer text-base"
@click.stop="setSelectRow(row)"
>
<MdiRadioChecked v-if="checked" />
<MdiRadioUnchecked v-else />
</span>
@ -34,214 +45,243 @@
<script setup lang="ts">
import { defineComponent, ref, computed, reactive, onMounted } from 'vue';
import { FsCrud } from '@fast-crud/fast-crud';
import { type VxeGridProps } from 'vxe-table'
import { type VxeGridProps } from 'vxe-table';
import { Page, useVbenModal } from '@vben/common-ui';
import { useVxeTable } from '#/hooks/vxeTable';
import { MdiAdd, MdiUpdate, MdiDelete, MdiImport, MdiExport, MdiRadioUnchecked, MdiRadioChecked } from '@vben/icons';
import {
MdiAdd,
MdiUpdate,
MdiDelete,
MdiImport,
MdiExport,
MdiRadioUnchecked,
MdiRadioChecked,
} from '@vben/icons';
import { getColumns } from './crud.tsx';
import { dict } from "@fast-crud/fast-crud";
import { getMonthStartAndEnd } from '#/utils/time'
import Apis from '#/api'
import { dict } from '@fast-crud/fast-crud';
import { getMonthStartAndEnd } from '#/utils/time';
import Apis from '#/api';
import dayjs from 'dayjs';
import { message } from "ant-design-vue";
import { message } from 'ant-design-vue';
import { Modal } from 'ant-design-vue';
import { useRouter } from 'vue-router'
import { useRouter } from 'vue-router';
import { SolarDay } from 'tyme4ts';
const router = useRouter();
const currentDate = ref(dayjs());
const currentMonth = computed(() => currentDate.value.format('YYYY年MM月'));
const prevMonth = () => {
currentDate.value = currentDate.value.subtract(1, 'month');
triggerProxy('reload')
triggerProxy('reload');
};
const nextMonth = () => {
currentDate.value = currentDate.value.add(1, 'month');
triggerProxy('reload')
triggerProxy('reload');
};
const checkedValue = ref('all')
const checkedValue = ref('all');
const exportSearchParams = ref<any>({
daterange: getMonthStartAndEnd(),
});
const searchRef = ref()
let isConfirmLoading = ref(false)
const searchRef = ref();
let isConfirmLoading = ref(false);
const [_Modal, modalApi] = useVbenModal({
async onConfirm() {
isConfirmLoading.value = true
isConfirmLoading.value = true;
try {
let params = {};
if (checkedValue.value == "daterange") {
if (checkedValue.value == 'daterange') {
params = {
startDate: exportSearchParams.value.daterange[0],
endDate: exportSearchParams.value.daterange[1],
};
}
let res = await Apis.zbgl.post_export({
params: params, config: {
meta: {
responseType: 'blob'
}
}
}).send();
message.success("导出成功");
modalApi.close()
let res = await Apis.zbgl
.post_export({
params: params,
config: {
meta: {
responseType: 'blob',
},
},
})
.send();
message.success('导出成功');
modalApi.close();
showExportModal.value = false;
} catch (error) {
console.error(error);
} finally {
isConfirmLoading.value = false
isConfirmLoading.value = false;
}
console.info("onConfirm");
console.info('onConfirm');
},
});
const { xGridRef, triggerProxy, gridProps } = useVxeTable({ ref: 'xGridRef' });
const treeData = ref([]);
const tableData = ref([])
const tableData = ref([]);
/** Hooks - 表格 */
const gridOptions = reactive(gridProps({
columns: getColumns({ type: "taizhang" }),
proxyConfig: {
autoLoad: false,
ajax: {
query: async ({ page }) => {
let data = await Apis.zbgl.get_queryZbInfo({ params: { pageNum: 1, pageSize: 100, duty_date: dayjs(currentDate.value).format("YYYY-MM") } })
for (const element of data.rows || []) {
var datas = dayjs(element.dutyDate).day();
var week = ["日", "一", "二", "三", "四", "五", "六"];
element.week = "星期" + week[datas];
}
tableData.value = data.rows
return data
const gridOptions = reactive(
gridProps({
columns: getColumns({ type: 'taizhang' }),
proxyConfig: {
autoLoad: false,
ajax: {
query: async ({ page }) => {
let data = await Apis.zbgl.get_queryZbInfo({
params: {
pageNum: 1,
pageSize: 100,
duty_date: dayjs(currentDate.value).format('YYYY-MM'),
},
});
for (const element of data.rows || []) {
var datas = dayjs(element.dutyDate).day();
var week = ['日', '一', '二', '三', '四', '五', '六'];
element.week = '星期' + week[datas];
}
tableData.value = data.rows;
return data;
},
},
}
},
rowStyle({ row, rowIndex }) {
if ((row && ["星期六", "星期日"].includes(row.week)) || row.week.length > 3) {
return {
backgroundColor: "#f6fbfb",
};
}
console.log(rowIndex)
},
pagerConfig: {
enabled: false
},
toolbarConfig: {
enabled: false
},
border: true,
headerCellStyle({ column }) {
if (["zzb", "ddy", "zb"].includes(column.field)) {
return {
"borderTop": '2px solid #000',
"borderLeft": '1px solid #000',
}
}
if (["dutyAllPeople", "dispatchPeople", "dutyPeople", "driver"].includes(column.field)) {
return {
"borderLeft": '1px solid #000',
"borderBottom": '2px solid #000',
}
}
if (["dutyAllPhone", "dutyAllTelphone", "dispatchPhone", 'dispatchTelphone', 'dutyPhone', 'dutyTelphone'].includes(column.field)) {
return {
"borderBottom": '2px solid #000',
}
}
if (["sj"].includes(column.field)) {
return {
"borderTop": '2px solid #000',
"borderLeft": '1px solid #000',
"borderRight": '1px solid #000',
}
}
if (["driverTelphone"].includes(column.field)) {
return {
"borderRight": '1px solid #000',
"borderBottom": '2px solid #000',
}
}
},
cellStyle({ row, column,rowIndex }) {
if (["dutyAllPeople", "dispatchPeople", "dutyPeople", "driver"].includes(column.field)) {
return {
"borderLeft": '1px solid #000',
}
}
if (["driverTelphone"].includes(column.field)) {
return {
"borderRight": '1px solid #000',
}
}
// if (rowIndex == tableData.value.length-1) {
// return {
// "borderBottom": '1px solid #000',
// }
// }
},
}));
function handleAdd() {
router.push('/bussiness-trip/edit')
}
function handleUpdate(row) {
router.push('/bussiness-trip/edit?id=' + row['guid'])
}
function handleUpload() {
// modalApi.setData({
// content: ' content',
// payload: ' payload',
// });
uploadModalApi.open();
}
function handleDelete(row) {
Modal.confirm({
title: '提示',
content: "是否确认删除该条记录?",
okType: 'danger',
onOk: async () => {
await Apis.meeting.post_deletes({ params: { ids: row['guid'] } })
message.success("删除成功");
triggerProxy("reload");
},
onCancel() {
console.log('Cancel');
rowStyle({ row, rowIndex }) {
if (
(row && ['星期六', '星期日'].includes(row.week)) ||
row.week.length > 3
) {
return {
backgroundColor: '#f6fbfb',
};
}
console.log(rowIndex);
},
});
}
pagerConfig: {
enabled: false,
},
toolbarConfig: {
enabled: false,
},
border: true,
headerCellStyle({ column }) {
let style: any = {};
if (['zzb', 'ddy', 'zb'].includes(column.field)) {
style = {
borderTop: '2px solid #000',
borderLeft: '1px solid #000',
};
}
if (['dutyDate'].includes(column.field)) {
style = {
borderTop: '2px solid #000',
borderLeft: '2px solid #000',
borderBottom: '2px solid #000',
};
}
if (['remark'].includes(column.field)) {
style = {
borderTop: '2px solid #000',
borderRight: '2px solid #000',
borderBottom: '2px solid #000',
};
}
if (
['dutyAllPeople', 'dispatchPeople', 'dutyPeople', 'driver'].includes(
column.field,
)
) {
style = {
borderLeft: '1px solid #000',
borderBottom: '2px solid #000',
};
}
if (
[
'dutyAllPhone',
'dutyAllTelphone',
'dispatchPhone',
'dispatchTelphone',
'dutyPhone',
'dutyTelphone',
].includes(column.field)
) {
style = {
borderBottom: '2px solid #000',
};
}
if (['sj'].includes(column.field)) {
style = {
borderTop: '2px solid #000',
borderLeft: '1px solid #000',
borderRight: '1px solid #000',
};
}
if (['driverTelphone'].includes(column.field)) {
style = {
borderRight: '1px solid #000',
borderBottom: '2px solid #000',
};
}
style['fontSize'] = '16px';
return style;
},
cellStyle({ row, column, rowIndex }) {
let style: any = {};
if (
['dutyAllPeople', 'dispatchPeople', 'dutyPeople', 'driver'].includes(
column.field,
)
) {
style = {
borderLeft: '1px solid #000',
fontWeight: '700',
};
}
if (['driverTelphone'].includes(column.field)) {
style = {
borderRight: '1px solid #000',
};
}
if (['dutyDate'].includes(column.field)) {
style = {
borderLeft: '2px solid #000',
};
}
if (['remark'].includes(column.field)) {
style = {
borderRight: '2px solid #000',
};
}
style['fontSize'] = '16px';
return style;
},
}),
);
/** 选中数据 */
const selectRow: Recordable = computed(() => {
@ -263,9 +303,8 @@ function handleCellClick({ row }) {
}
onMounted(() => {
triggerProxy('reload')
})
triggerProxy('reload');
});
</script>
<style></style>

View File

@ -556,7 +556,11 @@ onUnmounted(() => {
<ChooseUserModal class="w-[950px]" @row-click="handleChooseUserConfirm" />
<SpokenPersonEditModal class="w-[600px]" @success="loadDataByAddressor()" />
<a-affix :target="() => pageRef.bodyRef" :offset-top="0">
<a-affix
:target="() => pageRef.bodyRef"
:offset-top="0"
:style="{ zIndex: 50 }"
>
<div class="bg-white w-full pt-1 pl-1">
<a-space>
<vben-button variant="primary" @click="handleSubmit()">提交</vben-button>
@ -649,9 +653,9 @@ onUnmounted(() => {
<style scoped>
.sortable-tree-demo .drag-btn {
cursor: move;
font-size: 12px;
text-align: center;
cursor: move;
}
.sortable-tree-demo .vxe-body--row.sortable-ghost,

View File

@ -1,55 +0,0 @@
#!/bin/bash
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
LOG_FILE=${SCRIPT_DIR}/build-local-docker-image.log
ERROR=""
IMAGE_NAME="vben-admin-local"
function stop_and_remove_container() {
# Stop and remove the existing container
docker stop ${IMAGE_NAME} >/dev/null 2>&1
docker rm ${IMAGE_NAME} >/dev/null 2>&1
}
function remove_image() {
# Remove the existing image
docker rmi vben-admin-pro >/dev/null 2>&1
}
function install_dependencies() {
# Install all dependencies
cd ${SCRIPT_DIR}
pnpm install || ERROR="install_dependencies failed"
}
function build_image() {
# build docker
docker build . -f Dockerfile -t ${IMAGE_NAME} || ERROR="build_image failed"
}
function log_message() {
if [[ ${ERROR} != "" ]];
then
>&2 echo "build failed, Please check build-local-docker-image.log for more details"
>&2 echo "ERROR: ${ERROR}"
exit 1
else
echo "docker image with tag '${IMAGE_NAME}' built sussessfully. Use below sample command to run the container"
echo ""
echo "docker run -d -p 8010:8080 --name ${IMAGE_NAME} ${IMAGE_NAME}"
fi
}
echo "Info: Stopping and removing existing container and image" | tee ${LOG_FILE}
stop_and_remove_container
remove_image
echo "Info: Installing dependencies" | tee -a ${LOG_FILE}
install_dependencies 1>> ${LOG_FILE} 2>> ${LOG_FILE}
if [[ ${ERROR} == "" ]]; then
echo "Info: Building docker image" | tee -a ${LOG_FILE}
build_image 1>> ${LOG_FILE} 2>> ${LOG_FILE}
fi
log_message | tee -a ${LOG_FILE}

View File

@ -1,75 +0,0 @@
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
types {
application/javascript js mjs;
text/css css;
text/html html;
}
sendfile on;
# tcp_nopush on;
#keepalive_timeout 0;
# keepalive_timeout 65;
# gzip on;
# gzip_buffers 32 16k;
# gzip_comp_level 6;
# gzip_min_length 1k;
# gzip_static on;
# gzip_types text/plain
# text/css
# application/javascript
# application/json
# application/x-javascript
# text/xml
# application/xml
# application/xml+rss
# text/javascript; #设置压缩的文件类型
# gzip_vary on;
server {
listen 8080;
server_name localhost;
location / {
root /usr/share/nginx/html;
try_files $uri $uri/ /index.html;
index index.html;
# Enable CORS
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
return 204;
}
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
}

View File

@ -84,7 +84,7 @@ onMounted(() => {
</script>
<template>
<div class="w-[90%]" @keydown.enter.prevent="handleSubmit">
<div @keydown.enter.prevent="handleSubmit">
<slot name="title">
<Title>
<slot name="title">

File diff suppressed because it is too large Load Diff