feat:提交从库数据源管理、多币种管理
This commit is contained in:
parent
95b944518a
commit
1d5083b243
@ -8,11 +8,11 @@
|
||||
- **模块归属**: datai-salesforce-setting
|
||||
- **版本号**: v1.0
|
||||
- **创建日期**: 2026-01-14
|
||||
- **最后更新**: 2026-01-14
|
||||
- **最后更新**: 2026-01-24
|
||||
|
||||
## 功能描述
|
||||
|
||||
查询配置环境列表,支持分页查询和多条件过滤。返回的环境数据包含环境ID、环境名称、环境编码、ORG类型、环境描述、是否激活等信息,便于用户管理和切换不同环境。
|
||||
查询配置环境列表,支持分页查询和多条件过滤。返回的环境数据包含环境ID、环境名称、环境编码、ORG类型、环境描述、是否激活、是否有效等信息,便于用户管理和切换不同环境。
|
||||
|
||||
## 请求参数
|
||||
|
||||
@ -20,7 +20,7 @@
|
||||
|
||||
| 参数名 | 类型 | 必填 | 描述 | 示例 | 默认值 |
|
||||
|--------|------|------|------|------|--------|
|
||||
| pageNum | Integer | 否 | 页码 | 1 | 1 |
|
||||
| pageNum | Integer | 否 | 页码 |1 | 1 |
|
||||
| pageSize | Integer | 否 | 每页数量 | 10 | 10 |
|
||||
| deptId | Long | 否 | 部门ID | 1 | - |
|
||||
| environmentName | String | 否 | 环境名称 | 生产环境 | - |
|
||||
@ -28,6 +28,8 @@
|
||||
| orgType | String | 否 | ORG类型 | source | - |
|
||||
| description | String | 否 | 环境描述 | 生产环境配置 | - |
|
||||
| isActive | Boolean | 否 | 是否激活 | true | - |
|
||||
| isValid | Boolean | 否 | 是否有效 | true | - |
|
||||
| datasourceId | Long | 否 | 数据源ID | 1 | - |
|
||||
| remark | String | 否 | 备注 | - | - |
|
||||
| createBy | String | 否 | 创建人 | admin | - |
|
||||
| createTime | Date | 否 | 创建时间 | 2026-01-01 00:00:00 | - |
|
||||
@ -96,6 +98,8 @@
|
||||
| orgType | String | ORG类型(source/target) | source |
|
||||
| description | String | 环境描述 | 生产环境配置 |
|
||||
| isActive | Boolean | 是否激活 | true |
|
||||
| isValid | Boolean | 是否有效 | true |
|
||||
| datasourceId | Long | 数据源ID | 1 |
|
||||
| remark | String | 备注 | 源ORG生产环境 |
|
||||
| createBy | String | 创建人 | admin |
|
||||
| createTime | String | 创建时间 | 2026-01-01 10:00:00 |
|
||||
|
||||
@ -8,11 +8,11 @@
|
||||
- **模块归属**: datai-salesforce-setting
|
||||
- **版本号**: v1.0
|
||||
- **创建日期**: 2026-01-14
|
||||
- **最后更新**: 2026-01-14
|
||||
- **最后更新**: 2026-01-24
|
||||
|
||||
## 功能描述
|
||||
|
||||
根据环境ID获取配置环境的详细信息,包括环境ID、环境名称、环境编码、ORG类型、环境描述、是否激活等完整信息,用于查看或编辑环境配置。
|
||||
根据环境ID获取配置环境的详细信息,包括环境ID、环境名称、环境编码、ORG类型、环境描述、是否激活、是否有效等完整信息,用于查看或编辑环境配置。
|
||||
|
||||
## 请求参数
|
||||
|
||||
@ -66,6 +66,8 @@
|
||||
| orgType | String | ORG类型(source/target) | source |
|
||||
| description | String | 环境描述 | 生产环境配置 |
|
||||
| isActive | Boolean | 是否激活 | true |
|
||||
| isValid | Boolean | 是否有效 | true |
|
||||
| datasourceId | Long | 数据源ID | 1 |
|
||||
| remark | String | 备注 | 源ORG生产环境 |
|
||||
| createBy | String | 创建人 | admin |
|
||||
| createTime | String | 创建时间 | 2026-01-01 10:00:00 |
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
- **模块归属**: datai-salesforce-setting
|
||||
- **版本号**: v1.0
|
||||
- **创建日期**: 2026-01-14
|
||||
- **最后更新**: 2026-01-14
|
||||
- **最后更新**: 2026-01-24
|
||||
|
||||
## 功能描述
|
||||
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
- **模块归属**: datai-salesforce-setting
|
||||
- **版本号**: v1.0
|
||||
- **创建日期**: 2026-01-14
|
||||
- **最后更新**: 2026-01-14
|
||||
- **最后更新**: 2026-01-24
|
||||
|
||||
## 功能描述
|
||||
|
||||
|
||||
@ -0,0 +1,212 @@
|
||||
# 接口文档
|
||||
|
||||
## 接口信息
|
||||
|
||||
- **接口名称**: 初始化环境从库
|
||||
- **接口路径**: /setting/environment/initSlave
|
||||
- **请求方法**: POST
|
||||
- **模块归属**: datai-salesforce-setting
|
||||
- **版本号**: v1.0
|
||||
- **创建日期**: 2026-01-24
|
||||
- **最后更新**: 2026-01-24
|
||||
|
||||
## 功能描述
|
||||
|
||||
为指定的环境初始化从库数据源。该接口会从配置文件读取主库配置,自动生成从库名称(slave_环境编码),创建数据库,写入数据源配置表,注册数据源到 DataSourceManager,并验证连接有效性。从库一经创建,不允许任何修改、删除或重新初始化。
|
||||
|
||||
## 请求参数
|
||||
|
||||
### 请求参数
|
||||
|
||||
| 参数名 | 类型 | 必填 | 描述 | 示例 | 默认值 |
|
||||
|--------|------|------|------|------|--------|
|
||||
| environmentId | Long | 是 | 环境ID | 1 | - |
|
||||
|
||||
**参数说明**:
|
||||
- `environmentId`: 要初始化从库的环境ID,必须是已存在的环境
|
||||
|
||||
## 响应数据
|
||||
|
||||
### 成功响应
|
||||
|
||||
**HTTP 状态码**: 200 OK
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功",
|
||||
"data": {
|
||||
"id": 1,
|
||||
"dsName": "PROD",
|
||||
"dbName": "slave_PROD",
|
||||
"dbHost": "localhost",
|
||||
"dbPort": 3306,
|
||||
"dbType": "mysql",
|
||||
"username": "root",
|
||||
"password": "******",
|
||||
"status": "0",
|
||||
"createBy": "admin",
|
||||
"createTime": "2026-01-24 10:00:00",
|
||||
"updateBy": "admin",
|
||||
"updateTime": "2026-01-24 10:00:00"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
| 字段名 | 类型 | 描述 | 示例 |
|
||||
|--------|------|------|------|
|
||||
| code | Integer | 响应码 | 200 |
|
||||
| msg | String | 响应消息 | 操作成功 |
|
||||
| data | Object | 创建的数据源配置详细信息 | - |
|
||||
|
||||
**data 对象字段说明**:
|
||||
|
||||
| 字段名 | 类型 | 描述 | 示例 |
|
||||
|--------|------|------|------|
|
||||
| id | Long | 数据源ID | 1 |
|
||||
| dsName | String | 数据源名称(环境编码) | PROD |
|
||||
| dbName | String | 数据库名称 | slave_PROD |
|
||||
| dbHost | String | 数据库主机地址 | localhost |
|
||||
| dbPort | Integer | 数据库端口 | 3306 |
|
||||
| dbType | String | 数据库类型 | mysql |
|
||||
| username | String | 数据库用户名 | root |
|
||||
| password | String | 数据库密码(加密) | ****** |
|
||||
| status | String | 状态(0-正常,1-停用) | 0 |
|
||||
| createBy | String | 创建人 | admin |
|
||||
| createTime | String | 创建时间 | 2026-01-24 10:00:00 |
|
||||
| updateBy | String | 更新人 | admin |
|
||||
| updateTime | String | 更新时间 | 2026-01-24 10:00:00 |
|
||||
|
||||
### 失败响应
|
||||
|
||||
**HTTP 状态码**: 400/401/403/500
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 500,
|
||||
"msg": "数据源名称已存在:PROD",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
| 错误码 | 错误信息 | 描述 |
|
||||
|--------|----------|------|
|
||||
| 400 | 参数错误 | 参数验证失败 |
|
||||
| 401 | 您没有权限执行此操作 | 权限不足 |
|
||||
| 403 | 访问被拒绝 | 访问被拒绝 |
|
||||
| 500 | 数据源名称已存在:{环境编码} | 数据源已存在 |
|
||||
| 500 | 主库配置不存在 | 主库配置不存在 |
|
||||
| 500 | 数据库操作失败:{错误信息} | 数据库操作失败 |
|
||||
| 500 | 数据源配置写入失败 | 数据源配置写入失败 |
|
||||
| 500 | 数据源连接验证失败 | 数据源连接验证失败 |
|
||||
|
||||
## 接口示例
|
||||
|
||||
### 请求示例
|
||||
|
||||
```bash
|
||||
curl -X POST "http://localhost:8080/setting/environment/initSlave" \
|
||||
-H "Authorization: Bearer [token]" \
|
||||
-H "Content-Type: application/x-www-form-urlencoded" \
|
||||
-d "environmentId=1"
|
||||
```
|
||||
|
||||
### 响应示例
|
||||
|
||||
**成功**:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功",
|
||||
"data": {
|
||||
"id": 1,
|
||||
"dsName": "PROD",
|
||||
"dbName": "slave_PROD",
|
||||
"dbHost": "localhost",
|
||||
"dbPort": 3306,
|
||||
"dbType": "mysql",
|
||||
"username": "root",
|
||||
"password": "******",
|
||||
"status": "0"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**失败**:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 500,
|
||||
"msg": "数据源名称已存在:PROD",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
## 错误处理
|
||||
|
||||
1. **权限验证失败**: 检查用户是否具有 setting:environment:initSlave 权限
|
||||
2. **参数验证失败**: 检查必填参数是否完整,参数格式是否正确
|
||||
3. **主库配置不存在**: 检查 application-druid.yml 中是否配置了主库信息
|
||||
4. **数据源已存在**: 检查数据源名称是否已存在,如已存在则返回错误
|
||||
5. **数据库创建失败**: 检查数据库连接和权限,记录错误日志并返回错误信息
|
||||
6. **数据源配置写入失败**: 检查数据库连接和权限,记录错误日志并返回错误信息
|
||||
7. **数据源连接验证失败**: 检查数据源配置和连接,记录错误日志并返回错误信息
|
||||
8. **系统错误**: 记录错误日志并返回通用错误信息
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. 接口需要登录认证,需要携带有效的 token
|
||||
2. 接口需要 setting:environment:initSlave 权限
|
||||
3. 环境编码为必填项
|
||||
4. 从库名称自动生成为 slave_环境编码
|
||||
5. 数据库字符集为 utf8mb4,排序规则为 utf8mb4_general_ci
|
||||
6. 从库一经创建,不允许任何修改、删除或重新初始化
|
||||
7. 使用 Spring 事务保证原子性,验证失败时自动回滚
|
||||
8. 初始化操作会记录到操作日志中
|
||||
9. 初始化成功后会返回创建的数据源配置信息
|
||||
10. 主库配置从 application-druid.yml 配置文件中读取
|
||||
11. 初始化过程包括:创建数据库、写入配置、注册数据源、切换到从库、验证连接、切换回主库
|
||||
12. 建议在初始化前先查询确认环境信息
|
||||
|
||||
## 相关接口
|
||||
|
||||
- [查询配置环境列表](0001-environment-list.md) - 查询配置环境列表
|
||||
- [获取配置环境详细信息](0003-get-info.md) - 获取单个环境的详细信息
|
||||
- [切换当前环境](0007-switch-environment.md) - 切换当前环境
|
||||
- [获取当前激活的环境](0008-get-current-environment.md) - 获取当前激活的环境
|
||||
|
||||
## 实现细节
|
||||
|
||||
1. 接收环境ID参数
|
||||
2. 根据环境ID查询环境信息
|
||||
3. 从环境信息中获取环境编码
|
||||
4. 调用 IDataiConfigEnvironmentService 的 initSlaveDatasource 方法
|
||||
5. 从 application-druid.yml 配置文件中读取主库配置
|
||||
6. 生成从库名称(slave_环境编码)
|
||||
7. 检查数据源名称是否已存在
|
||||
8. 使用 JDBC 创建数据库(字符集:utf8mb4,排序规则:utf8mb4_general_ci)
|
||||
9. 写入数据源配置表
|
||||
10. 注册数据源到 DataSourceManager
|
||||
11. 切换到从库并验证连接有效性
|
||||
12. 切换回主库
|
||||
13. 使用 Spring 事务保证原子性,验证失败时自动回滚
|
||||
14. 返回创建的数据源配置信息
|
||||
|
||||
## 测试信息
|
||||
|
||||
### 测试环境
|
||||
|
||||
- **环境**: 本地开发环境
|
||||
- **版本**: v1.0
|
||||
|
||||
### 测试用例
|
||||
|
||||
| 测试场景 | 输入参数 | 预期结果 | 实际结果 | 状态 |
|
||||
|----------|----------|----------|----------|------|
|
||||
| 初始化生产环境从库 | environmentId=1 | 初始化成功 | 初始化成功 | 通过 |
|
||||
| 初始化测试环境从库 | environmentId=2 | 初始化成功 | 初始化成功 | 通过 |
|
||||
| 初始化已存在的从库 | environmentId=1(已存在) | 返回数据源已存在 | 返回数据源已存在 | 通过 |
|
||||
| 初始化不存在的环境 | environmentId=999 | 返回错误 | 返回错误 | 通过 |
|
||||
| 缺少必填参数 | 缺少environmentId | 返回参数错误 | 返回参数错误 | 通过 |
|
||||
| 无权限访问 | 无权限token | 返回401错误 | 返回401错误 | 通过 |
|
||||
@ -38,11 +38,11 @@ export function delEnvironment(id) {
|
||||
})
|
||||
}
|
||||
|
||||
export function switchEnvironment(data) {
|
||||
export function switchEnvironment(params) {
|
||||
return request({
|
||||
url: '/setting/environment/switch',
|
||||
method: 'post',
|
||||
data: data
|
||||
params: params
|
||||
})
|
||||
}
|
||||
|
||||
@ -53,3 +53,11 @@ export function getCurrentEnvironment(orgType) {
|
||||
params: { orgType }
|
||||
})
|
||||
}
|
||||
|
||||
export function initSlaveDatasource(environmentId) {
|
||||
return request({
|
||||
url: '/setting/environment/initSlave',
|
||||
method: 'post',
|
||||
params: { environmentId }
|
||||
})
|
||||
}
|
||||
|
||||
44
src/api/system/datasourceConfig.js
Normal file
44
src/api/system/datasourceConfig.js
Normal file
@ -0,0 +1,44 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 查询数据源管理列表
|
||||
export function listDatasourceConfig(query) {
|
||||
return request({
|
||||
url: '/system/datasourceConfig/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 查询数据源管理详细
|
||||
export function getDatasourceConfig(id) {
|
||||
return request({
|
||||
url: '/system/datasourceConfig/' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 新增数据源管理
|
||||
export function addDatasourceConfig(data) {
|
||||
return request({
|
||||
url: '/system/datasourceConfig',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 修改数据源管理
|
||||
export function updateDatasourceConfig(data) {
|
||||
return request({
|
||||
url: '/system/datasourceConfig',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除数据源管理
|
||||
export function delDatasourceConfig(id) {
|
||||
return request({
|
||||
url: '/system/datasourceConfig/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
44
src/api/system/exchangerate.js
Normal file
44
src/api/system/exchangerate.js
Normal file
@ -0,0 +1,44 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 查询汇率管理列表
|
||||
export function listExchangerate(query) {
|
||||
return request({
|
||||
url: '/system/exchangerate/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 查询汇率管理详细
|
||||
export function getExchangerate(id) {
|
||||
return request({
|
||||
url: '/system/exchangerate/' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 新增汇率管理
|
||||
export function addExchangerate(data) {
|
||||
return request({
|
||||
url: '/system/exchangerate',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 修改汇率管理
|
||||
export function updateExchangerate(data) {
|
||||
return request({
|
||||
url: '/system/exchangerate',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除汇率管理
|
||||
export function delExchangerate(id) {
|
||||
return request({
|
||||
url: '/system/exchangerate/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
@ -4,7 +4,10 @@
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>当前源环境</span>
|
||||
<el-tag v-if="currentEnvironment" type="success">{{ currentEnvironment.environmentName }}</el-tag>
|
||||
<el-tag v-if="currentEnvironment" type="success" effect="dark">
|
||||
<el-icon class="tag-icon"><Monitor /></el-icon>
|
||||
{{ currentEnvironment.environmentName }}
|
||||
</el-tag>
|
||||
<el-tag v-else type="info">未设置</el-tag>
|
||||
</div>
|
||||
</template>
|
||||
@ -24,39 +27,107 @@
|
||||
{{ currentEnvironment.isActive ? '是' : '否' }}
|
||||
</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="是否有效">
|
||||
<el-tag :type="currentEnvironment.isValid ? 'success' : 'danger'">
|
||||
{{ currentEnvironment.isValid ? '是' : '否' }}
|
||||
</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="数据源ID" v-if="currentEnvironment.datasourceId">
|
||||
{{ currentEnvironment.datasourceId }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="备注" :span="2" v-if="currentEnvironment.remark">
|
||||
{{ currentEnvironment.remark }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="创建人" v-if="currentEnvironment.createBy">
|
||||
{{ currentEnvironment.createBy }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="创建时间">
|
||||
{{ parseTime(currentEnvironment.createTime) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="更新人" v-if="currentEnvironment.updateBy">
|
||||
{{ currentEnvironment.updateBy }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="更新时间" v-if="currentEnvironment.updateTime">
|
||||
{{ parseTime(currentEnvironment.updateTime) }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
|
||||
<el-empty v-else description="暂无当前源环境" />
|
||||
<el-empty v-else description="暂无当前源环境" :image-size="60">
|
||||
<template #description>
|
||||
<p class="empty-tip">请先配置并激活源环境</p>
|
||||
</template>
|
||||
</el-empty>
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="never" class="mt10">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>源环境列表</span>
|
||||
<el-button type="primary" icon="Plus" @click="handleAdd" v-hasPermi="['setting:environment:add']">新增源环境</el-button>
|
||||
<div class="header-actions">
|
||||
<el-button type="primary" icon="Plus" @click="handleAdd" v-hasPermi="['setting:environment:add']">新增源环境</el-button>
|
||||
<el-button type="success" icon="Files" @click="handleInitSlave" v-hasPermi="['setting:environment:initSlave']">初始化从库</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-form :model="queryParams" ref="queryRef" :inline="true" label-width="68px" v-show="showSearch">
|
||||
<el-form-item label="环境名称" prop="environmentName">
|
||||
<el-input v-model="queryParams.environmentName" placeholder="请输入环境名称" clearable style="width: 200px" @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="环境编码" prop="environmentCode">
|
||||
<el-input v-model="queryParams.environmentCode" placeholder="请输入环境编码" clearable style="width: 200px" @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="是否激活" prop="isActive">
|
||||
<el-select v-model="queryParams.isActive" placeholder="是否激活" clearable style="width: 120px">
|
||||
<el-option label="是" :value="true" />
|
||||
<el-option label="否" :value="false" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否有效" prop="isValid">
|
||||
<el-select v-model="queryParams.isValid" placeholder="是否有效" clearable style="width: 120px">
|
||||
<el-option label="是" :value="true" />
|
||||
<el-option label="否" :value="false" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-table v-loading="loading" :data="environmentList">
|
||||
<el-table-column label="环境名称" align="center" prop="environmentName" />
|
||||
<el-table-column label="环境编码" align="center" prop="environmentCode" />
|
||||
<el-table-column label="环境描述" align="center" prop="description" show-overflow-tooltip />
|
||||
<el-table-column label="是否激活" align="center" prop="isActive">
|
||||
<el-table-column label="环境名称" align="center" prop="environmentName" min-width="120" />
|
||||
<el-table-column label="环境编码" align="center" prop="environmentCode" min-width="100" />
|
||||
<el-table-column label="环境描述" align="center" prop="description" show-overflow-tooltip min-width="150" />
|
||||
<el-table-column label="是否激活" align="center" prop="isActive" width="100">
|
||||
<template #default="scope">
|
||||
<el-tag :type="scope.row.isActive ? 'success' : 'danger'">
|
||||
<el-tag :type="scope.row.isActive ? 'success' : 'danger'" size="small">
|
||||
{{ scope.row.isActive ? '是' : '否' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="是否有效" align="center" prop="isValid" width="100">
|
||||
<template #default="scope">
|
||||
<el-tag :type="scope.row.isValid ? 'success' : 'danger'" size="small">
|
||||
{{ scope.row.isValid ? '是' : '否' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="数据源ID" align="center" prop="datasourceId" width="100" />
|
||||
<el-table-column label="备注" align="center" prop="remark" show-overflow-tooltip min-width="120" />
|
||||
<el-table-column label="创建人" align="center" prop="createBy" width="100" />
|
||||
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
|
||||
<template #default="scope">
|
||||
<span>{{ parseTime(scope.row.createTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" width="240" fixed="right">
|
||||
<el-table-column label="更新人" align="center" prop="updateBy" width="100" />
|
||||
<el-table-column label="更新时间" align="center" prop="updateTime" width="180">
|
||||
<template #default="scope">
|
||||
<span>{{ parseTime(scope.row.updateTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" width="280" fixed="right">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
v-if="scope.row.isActive && (!currentEnvironment || currentEnvironment.id !== scope.row.id)"
|
||||
@ -73,10 +144,12 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
||||
</el-card>
|
||||
|
||||
<el-dialog :title="title" v-model="open" width="600px" append-to-body>
|
||||
<el-form ref="environmentRef" :model="form" :rules="rules" label-width="100px">
|
||||
<el-dialog :title="title" v-model="open" width="700px" append-to-body>
|
||||
<el-form ref="environmentRef" :model="form" :rules="rules" label-width="120px">
|
||||
<el-form-item label="环境名称" prop="environmentName">
|
||||
<el-input v-model="form.environmentName" placeholder="请输入环境名称" />
|
||||
</el-form-item>
|
||||
@ -84,13 +157,19 @@
|
||||
<el-input v-model="form.environmentCode" placeholder="请输入环境编码(如:dev、test、prod)" />
|
||||
</el-form-item>
|
||||
<el-form-item label="环境描述" prop="description">
|
||||
<el-input v-model="form.description" type="textarea" placeholder="请输入环境描述" />
|
||||
<el-input v-model="form.description" type="textarea" :rows="3" placeholder="请输入环境描述" />
|
||||
</el-form-item>
|
||||
<el-form-item label="是否激活" prop="isActive">
|
||||
<el-switch v-model="form.isActive" />
|
||||
<el-switch v-model="form.isActive" active-text="激活" inactive-text="停用" />
|
||||
</el-form-item>
|
||||
<el-form-item label="是否有效" prop="isValid">
|
||||
<el-switch v-model="form.isValid" active-text="有效" inactive-text="无效" />
|
||||
</el-form-item>
|
||||
<el-form-item label="数据源ID" prop="datasourceId">
|
||||
<el-input-number v-model="form.datasourceId" placeholder="请输入数据源ID" :min="1" style="width: 100%" />
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="form.remark" type="textarea" placeholder="请输入备注" />
|
||||
<el-input v-model="form.remark" type="textarea" :rows="3" placeholder="请输入备注" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
@ -107,7 +186,7 @@
|
||||
<el-input v-model="switchForm.environmentCode" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item label="切换原因" prop="switchReason">
|
||||
<el-input v-model="switchForm.switchReason" type="textarea" placeholder="请输入切换原因" />
|
||||
<el-input v-model="switchForm.switchReason" type="textarea" :rows="3" placeholder="请输入切换原因" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
@ -117,12 +196,43 @@
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog title="初始化从库" v-model="initSlaveOpen" width="500px" append-to-body>
|
||||
<el-alert title="注意事项" type="warning" :closable="false" style="margin-bottom: 20px">
|
||||
<template #default>
|
||||
<ul style="margin: 0; padding-left: 20px;">
|
||||
<li>从库一经创建,不允许任何修改、删除或重新初始化</li>
|
||||
<li>从库名称自动生成为 slave_环境编码</li>
|
||||
<li>初始化过程包括:创建数据库、写入配置、注册数据源、验证连接</li>
|
||||
</ul>
|
||||
</template>
|
||||
</el-alert>
|
||||
<el-form ref="initSlaveRef" :model="initSlaveForm" :rules="initSlaveRules" label-width="100px">
|
||||
<el-form-item label="环境" prop="environmentId">
|
||||
<el-select v-model="initSlaveForm.environmentId" placeholder="请选择环境" style="width: 100%" filterable>
|
||||
<el-option
|
||||
v-for="env in environmentList"
|
||||
:key="env.id"
|
||||
:label="`${env.environmentName} (${env.environmentCode})`"
|
||||
:value="env.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button type="primary" @click="submitInitSlave" :loading="initSlaveLoading">确 定</el-button>
|
||||
<el-button @click="initSlaveOpen = false">取 消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { listEnvironment, getEnvironment, addEnvironment, updateEnvironment, delEnvironment, switchEnvironment, getCurrentEnvironment } from "@/api/setting/environment";
|
||||
import { listEnvironment, getEnvironment, addEnvironment, updateEnvironment, delEnvironment, switchEnvironment, getCurrentEnvironment, initSlaveDatasource } from "@/api/setting/environment";
|
||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
import { Monitor, Files } from '@element-plus/icons-vue';
|
||||
|
||||
const props = defineProps({
|
||||
currentEnvironment: {
|
||||
@ -136,8 +246,12 @@
|
||||
|
||||
const environmentList = ref([]);
|
||||
const loading = ref(true);
|
||||
const showSearch = ref(true);
|
||||
const total = ref(0);
|
||||
const open = ref(false);
|
||||
const switchOpen = ref(false);
|
||||
const initSlaveOpen = ref(false);
|
||||
const initSlaveLoading = ref(false);
|
||||
const title = ref("");
|
||||
|
||||
const form = ref({});
|
||||
@ -146,6 +260,19 @@
|
||||
switchReason: '手动切换',
|
||||
orgType: 'source'
|
||||
});
|
||||
const initSlaveForm = ref({
|
||||
environmentId: ''
|
||||
});
|
||||
|
||||
const queryParams = ref({
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
orgType: 'source',
|
||||
environmentName: null,
|
||||
environmentCode: null,
|
||||
isActive: null,
|
||||
isValid: null
|
||||
});
|
||||
|
||||
const rules = {
|
||||
environmentName: [
|
||||
@ -158,12 +285,19 @@
|
||||
|
||||
const switchRules = {};
|
||||
|
||||
const initSlaveRules = {
|
||||
environmentId: [
|
||||
{ required: true, message: "请选择环境", trigger: "change" }
|
||||
]
|
||||
};
|
||||
|
||||
const getList = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
const response = await listEnvironment({ orgType: 'source' });
|
||||
const response = await listEnvironment(queryParams.value);
|
||||
if (response.code === 200) {
|
||||
environmentList.value = response.rows || [];
|
||||
total.value = response.total || 0;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取源环境列表失败:', error);
|
||||
@ -172,12 +306,69 @@
|
||||
}
|
||||
};
|
||||
|
||||
const handleQuery = () => {
|
||||
queryParams.value.pageNum = 1;
|
||||
getList();
|
||||
};
|
||||
|
||||
const resetQuery = () => {
|
||||
proxy.resetForm("queryRef");
|
||||
queryParams.value = {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
orgType: 'source',
|
||||
environmentName: null,
|
||||
environmentCode: null,
|
||||
isActive: null,
|
||||
isValid: null
|
||||
};
|
||||
handleQuery();
|
||||
};
|
||||
|
||||
const handleAdd = () => {
|
||||
reset();
|
||||
open.value = true;
|
||||
title.value = "新增源环境";
|
||||
};
|
||||
|
||||
const handleInitSlave = () => {
|
||||
initSlaveForm.value = {
|
||||
environmentId: ''
|
||||
};
|
||||
initSlaveOpen.value = true;
|
||||
};
|
||||
|
||||
const submitInitSlave = async () => {
|
||||
proxy.$refs.initSlaveRef.validate(async (valid) => {
|
||||
if (valid) {
|
||||
try {
|
||||
const selectedEnv = environmentList.value.find(env => env.id === initSlaveForm.value.environmentId);
|
||||
const envName = selectedEnv ? selectedEnv.environmentName : initSlaveForm.value.environmentId;
|
||||
await ElMessageBox.confirm(`确定要为环境"${envName}"初始化从库吗?从库一经创建,不允许任何修改、删除或重新初始化。`, '警告', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
});
|
||||
initSlaveLoading.value = true;
|
||||
const response = await initSlaveDatasource(initSlaveForm.value.environmentId);
|
||||
if (response.code === 200) {
|
||||
ElMessage.success('从库初始化成功');
|
||||
initSlaveOpen.value = false;
|
||||
getList();
|
||||
} else {
|
||||
ElMessage.error(response.msg || '从库初始化失败');
|
||||
}
|
||||
} catch (error) {
|
||||
if (error !== 'cancel') {
|
||||
ElMessage.error(error.msg || '从库初始化失败');
|
||||
}
|
||||
} finally {
|
||||
initSlaveLoading.value = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const handleUpdate = async (row) => {
|
||||
reset();
|
||||
const id = row.id;
|
||||
@ -273,11 +464,25 @@
|
||||
orgType: 'source',
|
||||
description: null,
|
||||
isActive: true,
|
||||
isValid: true,
|
||||
datasourceId: null,
|
||||
remark: null
|
||||
};
|
||||
proxy.resetForm("environmentRef");
|
||||
};
|
||||
|
||||
const parseTime = (time) => {
|
||||
if (!time) return '';
|
||||
const date = new Date(time);
|
||||
const year = date.getFullYear();
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(date.getDate()).padStart(2, '0');
|
||||
const hours = String(date.getHours()).padStart(2, '0');
|
||||
const minutes = String(date.getMinutes()).padStart(2, '0');
|
||||
const seconds = String(date.getSeconds()).padStart(2, '0');
|
||||
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getList();
|
||||
});
|
||||
@ -291,6 +496,15 @@
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.header-actions {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.tag-icon {
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.current-env-card {
|
||||
background: #ffffff;
|
||||
border: 1px solid #e4e7ed;
|
||||
@ -317,4 +531,16 @@
|
||||
.mt10 {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.empty-tip {
|
||||
color: #909399;
|
||||
font-size: 13px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.dialog-footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 10px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -36,7 +36,10 @@
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>目标环境列表</span>
|
||||
<el-button type="primary" icon="Plus" @click="handleAdd" v-hasPermi="['setting:environment:add']">新增目标环境</el-button>
|
||||
<div class="header-actions">
|
||||
<el-button type="primary" icon="Plus" @click="handleAdd" v-hasPermi="['setting:environment:add']">新增目标环境</el-button>
|
||||
<el-button type="success" icon="Files" @click="handleInitSlave" v-hasPermi="['setting:environment:initSlave']">初始化从库</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -117,12 +120,43 @@
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog title="初始化从库" v-model="initSlaveOpen" width="500px" append-to-body>
|
||||
<el-alert title="注意事项" type="warning" :closable="false" style="margin-bottom: 20px">
|
||||
<template #default>
|
||||
<ul style="margin: 0; padding-left: 20px;">
|
||||
<li>从库一经创建,不允许任何修改、删除或重新初始化</li>
|
||||
<li>从库名称自动生成为 slave_环境编码</li>
|
||||
<li>初始化过程包括:创建数据库、写入配置、注册数据源、验证连接</li>
|
||||
</ul>
|
||||
</template>
|
||||
</el-alert>
|
||||
<el-form ref="initSlaveRef" :model="initSlaveForm" :rules="initSlaveRules" label-width="100px">
|
||||
<el-form-item label="环境" prop="environmentId">
|
||||
<el-select v-model="initSlaveForm.environmentId" placeholder="请选择环境" style="width: 100%" filterable>
|
||||
<el-option
|
||||
v-for="env in environmentList"
|
||||
:key="env.id"
|
||||
:label="`${env.environmentName} (${env.environmentCode})`"
|
||||
:value="env.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button type="primary" @click="submitInitSlave" :loading="initSlaveLoading">确 定</el-button>
|
||||
<el-button @click="initSlaveOpen = false">取 消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { listEnvironment, getEnvironment, addEnvironment, updateEnvironment, delEnvironment, switchEnvironment, getCurrentEnvironment } from "@/api/setting/environment";
|
||||
import { listEnvironment, getEnvironment, addEnvironment, updateEnvironment, delEnvironment, switchEnvironment, getCurrentEnvironment, initSlaveDatasource } from "@/api/setting/environment";
|
||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
import { Files } from '@element-plus/icons-vue';
|
||||
|
||||
const props = defineProps({
|
||||
currentEnvironment: {
|
||||
@ -138,6 +172,8 @@
|
||||
const loading = ref(true);
|
||||
const open = ref(false);
|
||||
const switchOpen = ref(false);
|
||||
const initSlaveOpen = ref(false);
|
||||
const initSlaveLoading = ref(false);
|
||||
const title = ref("");
|
||||
|
||||
const form = ref({});
|
||||
@ -146,6 +182,9 @@
|
||||
switchReason: '手动切换',
|
||||
orgType: 'target'
|
||||
});
|
||||
const initSlaveForm = ref({
|
||||
environmentId: ''
|
||||
});
|
||||
|
||||
const rules = {
|
||||
environmentName: [
|
||||
@ -158,6 +197,12 @@
|
||||
|
||||
const switchRules = {};
|
||||
|
||||
const initSlaveRules = {
|
||||
environmentId: [
|
||||
{ required: true, message: "请选择环境", trigger: "change" }
|
||||
]
|
||||
};
|
||||
|
||||
const getList = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
@ -178,6 +223,44 @@
|
||||
title.value = "新增目标环境";
|
||||
};
|
||||
|
||||
const handleInitSlave = () => {
|
||||
initSlaveForm.value = {
|
||||
environmentId: ''
|
||||
};
|
||||
initSlaveOpen.value = true;
|
||||
};
|
||||
|
||||
const submitInitSlave = async () => {
|
||||
proxy.$refs.initSlaveRef.validate(async (valid) => {
|
||||
if (valid) {
|
||||
try {
|
||||
const selectedEnv = environmentList.value.find(env => env.id === initSlaveForm.value.environmentId);
|
||||
const envName = selectedEnv ? selectedEnv.environmentName : initSlaveForm.value.environmentId;
|
||||
await ElMessageBox.confirm(`确定要为环境"${envName}"初始化从库吗?从库一经创建,不允许任何修改、删除或重新初始化。`, '警告', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
});
|
||||
initSlaveLoading.value = true;
|
||||
const response = await initSlaveDatasource(initSlaveForm.value.environmentId);
|
||||
if (response.code === 200) {
|
||||
ElMessage.success('从库初始化成功');
|
||||
initSlaveOpen.value = false;
|
||||
getList();
|
||||
} else {
|
||||
ElMessage.error(response.msg || '从库初始化失败');
|
||||
}
|
||||
} catch (error) {
|
||||
if (error !== 'cancel') {
|
||||
ElMessage.error(error.msg || '从库初始化失败');
|
||||
}
|
||||
} finally {
|
||||
initSlaveLoading.value = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const handleUpdate = async (row) => {
|
||||
reset();
|
||||
const id = row.id;
|
||||
@ -278,6 +361,18 @@
|
||||
proxy.resetForm("environmentRef");
|
||||
};
|
||||
|
||||
const parseTime = (time) => {
|
||||
if (!time) return '';
|
||||
const date = new Date(time);
|
||||
const year = date.getFullYear();
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(date.getDate()).padStart(2, '0');
|
||||
const hours = String(date.getHours()).padStart(2, '0');
|
||||
const minutes = String(date.getMinutes()).padStart(2, '0');
|
||||
const seconds = String(date.getSeconds()).padStart(2, '0');
|
||||
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getList();
|
||||
});
|
||||
@ -291,6 +386,11 @@
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.header-actions {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.current-env-card {
|
||||
background: #ffffff;
|
||||
border: 1px solid #e4e7ed;
|
||||
@ -317,4 +417,10 @@
|
||||
.mt10 {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.dialog-footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 10px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-tabs v-model="activeTab" type="border-card">
|
||||
<el-tabs v-model="activeTab" type="border-card" v-loading="environmentLoading">
|
||||
<el-tab-pane label="源环境管理" name="sourceEnvironment">
|
||||
<SourceEnvironmentTab :current-environment="sourceEnvironment" @environment-switched="handleSourceEnvironmentSwitched" />
|
||||
</el-tab-pane>
|
||||
@ -50,10 +50,12 @@
|
||||
|
||||
const activeTab = ref('sourceEnvironment');
|
||||
const refreshLoading = ref(false);
|
||||
const environmentLoading = ref(false);
|
||||
const sourceEnvironment = ref(null);
|
||||
const targetEnvironment = ref(null);
|
||||
|
||||
const loadCurrentEnvironments = async () => {
|
||||
environmentLoading.value = true;
|
||||
try {
|
||||
const [sourceResponse, targetResponse] = await Promise.all([
|
||||
getCurrentEnvironment('source'),
|
||||
@ -61,12 +63,19 @@
|
||||
]);
|
||||
if (sourceResponse.code === 200) {
|
||||
sourceEnvironment.value = sourceResponse.data;
|
||||
} else {
|
||||
console.warn('获取源环境失败:', sourceResponse.msg);
|
||||
}
|
||||
if (targetResponse.code === 200) {
|
||||
targetEnvironment.value = targetResponse.data;
|
||||
} else {
|
||||
console.warn('获取目标环境失败:', targetResponse.msg);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取当前环境失败:', error);
|
||||
ElMessage.warning('获取环境信息失败,部分功能可能不可用');
|
||||
} finally {
|
||||
environmentLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
546
src/views/system/datasourceConfig/index.vue
Normal file
546
src/views/system/datasourceConfig/index.vue
Normal file
@ -0,0 +1,546 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-card shadow="never" body-class="search-card">
|
||||
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
|
||||
<el-form-item label="数据源名称" prop="dsName">
|
||||
<el-input
|
||||
v-model="queryParams.dsName"
|
||||
placeholder="请输入数据源名称"
|
||||
clearable
|
||||
@keyup.enter="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="数据库名称" prop="dbName">
|
||||
<el-input
|
||||
v-model="queryParams.dbName"
|
||||
placeholder="请输入数据库名称"
|
||||
clearable
|
||||
@keyup.enter="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="数据库主机" prop="dbHost">
|
||||
<el-input
|
||||
v-model="queryParams.dbHost"
|
||||
placeholder="请输入数据库主机"
|
||||
clearable
|
||||
@keyup.enter="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="数据库端口" prop="dbPort">
|
||||
<el-input
|
||||
v-model="queryParams.dbPort"
|
||||
placeholder="请输入数据库端口"
|
||||
clearable
|
||||
@keyup.enter="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="用户名" prop="username">
|
||||
<el-input
|
||||
v-model="queryParams.username"
|
||||
placeholder="请输入用户名"
|
||||
clearable
|
||||
@keyup.enter="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="密码" prop="password">
|
||||
<el-input
|
||||
v-model="queryParams.password"
|
||||
placeholder="请输入密码"
|
||||
clearable
|
||||
@keyup.enter="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="never" class="mt10">
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
icon="Plus"
|
||||
@click="handleAdd"
|
||||
v-hasPermi="['system:datasourceConfig:add']"
|
||||
>新增</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="warning"
|
||||
plain
|
||||
icon="Download"
|
||||
@click="handleExport"
|
||||
v-hasPermi="['system:datasourceConfig:export']"
|
||||
>导出</el-button>
|
||||
</el-col>
|
||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
<el-table v-loading="loading" :data="datasourceConfigList" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="主键ID" align="center" prop="id" />
|
||||
<el-table-column label="数据源名称" align="center" prop="dsName" />
|
||||
<el-table-column label="数据库名称" align="center" prop="dbName" />
|
||||
<el-table-column label="数据库主机" align="center" prop="dbHost" />
|
||||
<el-table-column label="数据库端口" align="center" prop="dbPort" />
|
||||
<el-table-column label="用户名" align="center" prop="username" />
|
||||
<el-table-column label="密码" align="center" prop="password" />
|
||||
<el-table-column label="数据库类型" align="center" prop="dbType" />
|
||||
<el-table-column label="状态" align="center" prop="status" />
|
||||
<el-table-column label="备注" align="center" prop="remark" />
|
||||
<el-table-column label="操作" align="center" fixed="right" class-name="small-padding fixed-width">
|
||||
<template #default="scope">
|
||||
<el-button link type="primary" icon="View" @click="handleDetail(scope.row)" v-hasPermi="['system:datasourceConfig:query']">详情</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
v-show="total>0"
|
||||
:total="total"
|
||||
v-model:page="queryParams.pageNum"
|
||||
v-model:limit="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</el-card>
|
||||
|
||||
<el-dialog :title="title" v-model="open" width="600px" append-to-body>
|
||||
<el-form ref="datasourceConfigRef" :model="form" :rules="rules" label-width="100px">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="数据源名称" prop="dsName">
|
||||
<el-input v-model="form.dsName" placeholder="请输入数据源名称" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="数据库名称" prop="dbName">
|
||||
<el-input v-model="form.dbName" placeholder="请输入数据库名称" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="数据库主机" prop="dbHost">
|
||||
<el-input v-model="form.dbHost" placeholder="请输入数据库主机" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="数据库端口" prop="dbPort">
|
||||
<el-input v-model="form.dbPort" placeholder="请输入数据库端口" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="用户名" prop="username">
|
||||
<el-input v-model="form.username" placeholder="请输入用户名" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="密码" prop="password">
|
||||
<el-input v-model="form.password" placeholder="请输入密码" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-drawer :title="isEditMode ? '修改数据源管理' : '数据源管理详情'" v-model="openDetail" size="60%">
|
||||
|
||||
<div v-show="!isEditMode">
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item label="数据源名称">
|
||||
{{ detailForm.dsName }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="数据库名称">
|
||||
{{ detailForm.dbName }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="数据库主机">
|
||||
{{ detailForm.dbHost }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="数据库端口">
|
||||
{{ detailForm.dbPort }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="用户名">
|
||||
{{ detailForm.username }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="密码">
|
||||
{{ detailForm.password }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="数据库类型">
|
||||
{{ detailForm.dbType }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="状态">
|
||||
{{ detailForm.status }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="备注">
|
||||
{{ detailForm.remark }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="创建者">
|
||||
{{ detailForm.createBy }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="创建时间">
|
||||
<span>{{ parseTime(detailForm.createTime, '{y}-{m}-{d}') }}</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="更新者">
|
||||
{{ detailForm.updateBy }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="更新时间">
|
||||
<span>{{ parseTime(detailForm.updateTime, '{y}-{m}-{d}') }}</span>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
|
||||
<div v-show="isEditMode">
|
||||
<el-form ref="datasourceConfigDrawerRef" :model="form" :rules="rules" label-width="100px">
|
||||
<el-row :gutter="24">
|
||||
|
||||
|
||||
<el-col :span="12">
|
||||
<el-form-item label="数据源名称" prop="dsName">
|
||||
<el-input v-model="form.dsName" placeholder="请输入数据源名称" style="width: 100%"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
|
||||
<el-col :span="12">
|
||||
<el-form-item label="数据库名称" prop="dbName">
|
||||
<el-input v-model="form.dbName" placeholder="请输入数据库名称" style="width: 100%"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
|
||||
<el-col :span="12">
|
||||
<el-form-item label="数据库主机" prop="dbHost">
|
||||
<el-input v-model="form.dbHost" placeholder="请输入数据库主机" style="width: 100%"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
|
||||
<el-col :span="12">
|
||||
<el-form-item label="数据库端口" prop="dbPort">
|
||||
<el-input v-model="form.dbPort" placeholder="请输入数据库端口" style="width: 100%"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
|
||||
<el-col :span="12">
|
||||
<el-form-item label="用户名" prop="username">
|
||||
<el-input v-model="form.username" placeholder="请输入用户名" style="width: 100%"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
|
||||
<el-col :span="12">
|
||||
<el-form-item label="密码" prop="password">
|
||||
<el-input v-model="form.password" placeholder="请输入密码" style="width: 100%"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
|
||||
<el-col :span="12">
|
||||
</el-col>
|
||||
|
||||
|
||||
<el-col :span="12">
|
||||
</el-col>
|
||||
|
||||
|
||||
<el-col :span="24">
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<div class="drawer-footer" style="display: flex; justify-content: flex-end; gap: 10px;">
|
||||
<div v-if="!isEditMode">
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
icon="Edit"
|
||||
@click="handleEnterEditMode"
|
||||
v-hasPermi="['system:datasourceConfig:edit']"
|
||||
>修改资料</el-button>
|
||||
<el-button
|
||||
type="danger"
|
||||
plain
|
||||
icon="Delete"
|
||||
@click="handleDeleteFromDetail"
|
||||
v-hasPermi="['system:datasourceConfig:remove']"
|
||||
>删除记录</el-button>
|
||||
<el-button @click="openDetail = false">关 闭</el-button>
|
||||
</div>
|
||||
|
||||
<div v-else>
|
||||
<el-button type="primary" @click="submitDrawerForm">保存提交</el-button>
|
||||
<el-button @click="isEditMode = false">取消修改</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="DatasourceConfig">
|
||||
import { listDatasourceConfig, getDatasourceConfig, delDatasourceConfig, addDatasourceConfig, updateDatasourceConfig } from "@/api/system/datasourceConfig";
|
||||
const { proxy } = getCurrentInstance();
|
||||
|
||||
const datasourceConfigList = ref([]);
|
||||
const open = ref(false);
|
||||
const loading = ref(true);
|
||||
const showSearch = ref(true);
|
||||
const ids = ref([]);
|
||||
const single = ref(true);
|
||||
const multiple = ref(true);
|
||||
const total = ref(0);
|
||||
const title = ref("");
|
||||
|
||||
// 详情与编辑相关变量
|
||||
const openDetail = ref(false);
|
||||
const isEditMode = ref(false); // 控制查看/编辑模式
|
||||
const detailForm = ref({});
|
||||
|
||||
|
||||
const data = reactive({
|
||||
form: {},
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
dsName: null,
|
||||
dbName: null,
|
||||
dbHost: null,
|
||||
dbPort: null,
|
||||
username: null,
|
||||
password: null,
|
||||
dbType: null,
|
||||
status: null,
|
||||
},
|
||||
rules: {
|
||||
dsName: [
|
||||
{ required: true, message: "数据源名称不能为空", trigger: "blur" }
|
||||
],
|
||||
dbName: [
|
||||
{ required: true, message: "数据库名称不能为空", trigger: "blur" }
|
||||
],
|
||||
dbHost: [
|
||||
{ required: true, message: "数据库主机不能为空", trigger: "blur" }
|
||||
],
|
||||
dbPort: [
|
||||
{ required: true, message: "数据库端口不能为空", trigger: "blur" }
|
||||
],
|
||||
username: [
|
||||
{ required: true, message: "用户名不能为空", trigger: "blur" }
|
||||
],
|
||||
password: [
|
||||
{ required: true, message: "密码不能为空", trigger: "blur" }
|
||||
],
|
||||
dbType: [
|
||||
{ required: true, message: "数据库类型不能为空", trigger: "change" }
|
||||
],
|
||||
status: [
|
||||
{ required: true, message: "状态不能为空", trigger: "change" }
|
||||
],
|
||||
createBy: [
|
||||
{ required: true, message: "创建者不能为空", trigger: "blur" }
|
||||
],
|
||||
createTime: [
|
||||
{ required: true, message: "创建时间不能为空", trigger: "blur" }
|
||||
],
|
||||
updateBy: [
|
||||
{ required: true, message: "更新者不能为空", trigger: "blur" }
|
||||
],
|
||||
updateTime: [
|
||||
{ required: true, message: "更新时间不能为空", trigger: "blur" }
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
const { queryParams, form, rules } = toRefs(data);
|
||||
|
||||
/** 查询列表 */
|
||||
function getList() {
|
||||
loading.value = true;
|
||||
listDatasourceConfig(queryParams.value).then(response => {
|
||||
datasourceConfigList.value = response.rows;
|
||||
total.value = response.total;
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
// 取消按钮
|
||||
function cancel() {
|
||||
open.value = false;
|
||||
reset();
|
||||
}
|
||||
|
||||
// 表单重置
|
||||
function reset() {
|
||||
form.value = {
|
||||
id: null,
|
||||
dsName: null,
|
||||
dbName: null,
|
||||
dbHost: null,
|
||||
dbPort: null,
|
||||
username: null,
|
||||
password: null,
|
||||
dbType: null,
|
||||
status: null,
|
||||
remark: null,
|
||||
createBy: null,
|
||||
createTime: null,
|
||||
updateBy: null,
|
||||
updateTime: null
|
||||
};
|
||||
proxy.resetForm("datasourceConfigRef");
|
||||
proxy.resetForm("datasourceConfigDrawerRef");
|
||||
}
|
||||
|
||||
/** 搜索按钮操作 */
|
||||
function handleQuery() {
|
||||
queryParams.value.pageNum = 1;
|
||||
getList();
|
||||
}
|
||||
|
||||
/** 重置按钮操作 */
|
||||
function resetQuery() {
|
||||
proxy.resetForm("queryRef");
|
||||
handleQuery();
|
||||
}
|
||||
|
||||
// 多选框选中数据
|
||||
function handleSelectionChange(selection) {
|
||||
ids.value = selection.map(item => item.id);
|
||||
single.value = selection.length != 1;
|
||||
multiple.value = !selection.length;
|
||||
}
|
||||
|
||||
/** 新增按钮操作 */
|
||||
function handleAdd() {
|
||||
reset();
|
||||
open.value = true;
|
||||
title.value = "添加数据源管理";
|
||||
}
|
||||
|
||||
/** 修改按钮操作 (仅用于弹窗) */
|
||||
function handleUpdate(row) {
|
||||
reset();
|
||||
const _id = row.id || ids.value;
|
||||
getDatasourceConfig(_id).then(response => {
|
||||
form.value = response.data;
|
||||
open.value = true;
|
||||
title.value = "修改数据源管理";
|
||||
});
|
||||
}
|
||||
|
||||
/** 详情按钮操作 */
|
||||
function handleDetail(row) {
|
||||
reset();
|
||||
// 详情前重置表单状态
|
||||
isEditMode.value = false; // 默认进入查看模式
|
||||
const _id = row.id;
|
||||
getDatasourceConfig(_id).then(response => {
|
||||
detailForm.value = response.data;
|
||||
openDetail.value = true;
|
||||
});
|
||||
}
|
||||
|
||||
/** 进入编辑模式 */
|
||||
function handleEnterEditMode() {
|
||||
// 从 detailForm 同步数据到 form,准备编辑
|
||||
const row = detailForm.value;
|
||||
const _id = row.id;
|
||||
|
||||
// 重新获取最新数据以填充表单,保证格式(如checkbox数组)正确
|
||||
getDatasourceConfig(_id).then(response => {
|
||||
form.value = response.data;
|
||||
isEditMode.value = true; // 切换到编辑视图
|
||||
});
|
||||
}
|
||||
|
||||
/** 抽屉内表单提交 */
|
||||
function submitDrawerForm() {
|
||||
proxy.$refs["datasourceConfigDrawerRef"].validate(valid => {
|
||||
if (valid) {
|
||||
if (form.value.id != null) {
|
||||
updateDatasourceConfig(form.value).then(response => {
|
||||
proxy.$modal.msgSuccess("修改成功");
|
||||
// 修改成功后,刷新详情数据并切回查看模式
|
||||
detailForm.value = JSON.parse(JSON.stringify(form.value));
|
||||
// 注意:如果form数据和详情展示格式有较大差异(如split前后),最好重新调用get详情
|
||||
handleDetail(form.value);
|
||||
getList();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** 详情内删除按钮 */
|
||||
function handleDeleteFromDetail() {
|
||||
const row = detailForm.value;
|
||||
handleDelete(row).then(() => {
|
||||
openDetail.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
/** 常规弹窗提交按钮 */
|
||||
function submitForm() {
|
||||
proxy.$refs["datasourceConfigRef"].validate(valid => {
|
||||
if (valid) {
|
||||
if (form.value.id != null) {
|
||||
updateDatasourceConfig(form.value).then(response => {
|
||||
proxy.$modal.msgSuccess("修改成功");
|
||||
open.value = false;
|
||||
getList();
|
||||
});
|
||||
} else {
|
||||
addDatasourceConfig(form.value).then(response => {
|
||||
proxy.$modal.msgSuccess("新增成功");
|
||||
open.value = false;
|
||||
getList();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** 删除按钮操作 */
|
||||
function handleDelete(row) {
|
||||
const _ids = row.id || ids.value;
|
||||
return proxy.$modal.confirm('是否确认删除数据源管理编号为"' + _ids + '"的数据项?').then(function() {
|
||||
return delDatasourceConfig(_ids);
|
||||
}).then(() => {
|
||||
getList();
|
||||
proxy.$modal.msgSuccess("删除成功");
|
||||
}).catch(() => {});
|
||||
}
|
||||
|
||||
|
||||
/** 导出按钮操作 */
|
||||
function handleExport() {
|
||||
proxy.download('system/datasourceConfig/export', {
|
||||
...queryParams.value
|
||||
}, `datasourceConfig_${new Date().getTime()}.xlsx`)
|
||||
}
|
||||
|
||||
getList();
|
||||
</script>
|
||||
488
src/views/system/exchangerate/index.vue
Normal file
488
src/views/system/exchangerate/index.vue
Normal file
@ -0,0 +1,488 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-card shadow="never" body-class="search-card">
|
||||
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
|
||||
<el-form-item label="源货币代码" prop="fromCurrency">
|
||||
<el-input
|
||||
v-model="queryParams.fromCurrency"
|
||||
placeholder="请输入源货币代码"
|
||||
clearable
|
||||
@keyup.enter="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="目标货币代码" prop="toCurrency">
|
||||
<el-input
|
||||
v-model="queryParams.toCurrency"
|
||||
placeholder="请输入目标货币代码"
|
||||
clearable
|
||||
@keyup.enter="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="汇率" prop="rate">
|
||||
<el-input
|
||||
v-model="queryParams.rate"
|
||||
placeholder="请输入汇率"
|
||||
clearable
|
||||
@keyup.enter="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="汇率日期" prop="rateDate">
|
||||
<el-date-picker clearable
|
||||
v-model="queryParams.rateDate"
|
||||
type="date"
|
||||
value-format="YYYY-MM-DD"
|
||||
placeholder="请选择汇率日期">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
<el-form-item label="汇率来源" prop="source">
|
||||
<el-input
|
||||
v-model="queryParams.source"
|
||||
placeholder="请输入汇率来源"
|
||||
clearable
|
||||
@keyup.enter="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="never" class="mt10">
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
icon="Plus"
|
||||
@click="handleAdd"
|
||||
v-hasPermi="['system:exchangerate:add']"
|
||||
>新增</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="warning"
|
||||
plain
|
||||
icon="Download"
|
||||
@click="handleExport"
|
||||
v-hasPermi="['system:exchangerate:export']"
|
||||
>导出</el-button>
|
||||
</el-col>
|
||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
<el-table v-loading="loading" :data="exchangerateList" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="主键ID" align="center" prop="id" />
|
||||
<el-table-column label="源货币代码" align="center" prop="fromCurrency" />
|
||||
<el-table-column label="目标货币代码" align="center" prop="toCurrency" />
|
||||
<el-table-column label="汇率" align="center" prop="rate" />
|
||||
<el-table-column label="汇率日期" align="center" prop="rateDate" width="180">
|
||||
<template #default="scope">
|
||||
<span>{{ parseTime(scope.row.rateDate, '{y}-{m}-{d}') }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="汇率来源" align="center" prop="source" />
|
||||
<el-table-column label="备注" align="center" prop="remark" />
|
||||
<el-table-column label="操作" align="center" fixed="right" class-name="small-padding fixed-width">
|
||||
<template #default="scope">
|
||||
<el-button link type="primary" icon="View" @click="handleDetail(scope.row)" v-hasPermi="['system:exchangerate:query']">详情</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
v-show="total>0"
|
||||
:total="total"
|
||||
v-model:page="queryParams.pageNum"
|
||||
v-model:limit="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</el-card>
|
||||
|
||||
<el-dialog :title="title" v-model="open" width="600px" append-to-body>
|
||||
<el-form ref="exchangerateRef" :model="form" :rules="rules" label-width="100px">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="源货币代码" prop="fromCurrency">
|
||||
<el-input v-model="form.fromCurrency" placeholder="请输入源货币代码" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="目标货币代码" prop="toCurrency">
|
||||
<el-input v-model="form.toCurrency" placeholder="请输入目标货币代码" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="汇率" prop="rate">
|
||||
<el-input v-model="form.rate" placeholder="请输入汇率" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="汇率日期" prop="rateDate">
|
||||
<el-date-picker clearable
|
||||
v-model="form.rateDate"
|
||||
type="date"
|
||||
value-format="YYYY-MM-DD"
|
||||
style="width: 100%"
|
||||
placeholder="请选择汇率日期">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="汇率来源" prop="source">
|
||||
<el-input v-model="form.source" placeholder="请输入汇率来源" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-drawer :title="isEditMode ? '修改汇率管理' : '汇率管理详情'" v-model="openDetail" size="60%">
|
||||
|
||||
<div v-show="!isEditMode">
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item label="源货币代码">
|
||||
{{ detailForm.fromCurrency }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="目标货币代码">
|
||||
{{ detailForm.toCurrency }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="汇率">
|
||||
{{ detailForm.rate }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="汇率日期">
|
||||
<span>{{ parseTime(detailForm.rateDate, '{y}-{m}-{d}') }}</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="汇率来源">
|
||||
{{ detailForm.source }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="创建者">
|
||||
{{ detailForm.createBy }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="创建时间">
|
||||
<span>{{ parseTime(detailForm.createTime, '{y}-{m}-{d}') }}</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="更新者">
|
||||
{{ detailForm.updateBy }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="更新时间">
|
||||
<span>{{ parseTime(detailForm.updateTime, '{y}-{m}-{d}') }}</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="备注">
|
||||
{{ detailForm.remark }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
|
||||
<div v-show="isEditMode">
|
||||
<el-form ref="exchangerateDrawerRef" :model="form" :rules="rules" label-width="100px">
|
||||
<el-row :gutter="24">
|
||||
|
||||
|
||||
<el-col :span="12">
|
||||
<el-form-item label="源货币代码" prop="fromCurrency">
|
||||
<el-input v-model="form.fromCurrency" placeholder="请输入源货币代码" style="width: 100%"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
|
||||
<el-col :span="12">
|
||||
<el-form-item label="目标货币代码" prop="toCurrency">
|
||||
<el-input v-model="form.toCurrency" placeholder="请输入目标货币代码" style="width: 100%"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
|
||||
<el-col :span="12">
|
||||
<el-form-item label="汇率" prop="rate">
|
||||
<el-input v-model="form.rate" placeholder="请输入汇率" style="width: 100%"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
|
||||
<el-col :span="12">
|
||||
<el-form-item label="汇率日期" prop="rateDate">
|
||||
<el-date-picker clearable
|
||||
v-model="form.rateDate"
|
||||
type="date"
|
||||
value-format="YYYY-MM-DD"
|
||||
style="width: 100%"
|
||||
placeholder="请选择汇率日期">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
|
||||
<el-col :span="12">
|
||||
<el-form-item label="汇率来源" prop="source">
|
||||
<el-input v-model="form.source" placeholder="请输入汇率来源" style="width: 100%"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
|
||||
<el-col :span="24">
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<div class="drawer-footer" style="display: flex; justify-content: flex-end; gap: 10px;">
|
||||
<div v-if="!isEditMode">
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
icon="Edit"
|
||||
@click="handleEnterEditMode"
|
||||
v-hasPermi="['system:exchangerate:edit']"
|
||||
>修改资料</el-button>
|
||||
<el-button
|
||||
type="danger"
|
||||
plain
|
||||
icon="Delete"
|
||||
@click="handleDeleteFromDetail"
|
||||
v-hasPermi="['system:exchangerate:remove']"
|
||||
>删除记录</el-button>
|
||||
<el-button @click="openDetail = false">关 闭</el-button>
|
||||
</div>
|
||||
|
||||
<div v-else>
|
||||
<el-button type="primary" @click="submitDrawerForm">保存提交</el-button>
|
||||
<el-button @click="isEditMode = false">取消修改</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="Exchangerate">
|
||||
import { listExchangerate, getExchangerate, delExchangerate, addExchangerate, updateExchangerate } from "@/api/system/exchangerate";
|
||||
const { proxy } = getCurrentInstance();
|
||||
|
||||
const exchangerateList = ref([]);
|
||||
const open = ref(false);
|
||||
const loading = ref(true);
|
||||
const showSearch = ref(true);
|
||||
const ids = ref([]);
|
||||
const single = ref(true);
|
||||
const multiple = ref(true);
|
||||
const total = ref(0);
|
||||
const title = ref("");
|
||||
|
||||
// 详情与编辑相关变量
|
||||
const openDetail = ref(false);
|
||||
const isEditMode = ref(false); // 控制查看/编辑模式
|
||||
const detailForm = ref({});
|
||||
|
||||
|
||||
const data = reactive({
|
||||
form: {},
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
fromCurrency: null,
|
||||
toCurrency: null,
|
||||
rate: null,
|
||||
rateDate: null,
|
||||
source: null,
|
||||
},
|
||||
rules: {
|
||||
fromCurrency: [
|
||||
{ required: true, message: "源货币代码不能为空", trigger: "blur" }
|
||||
],
|
||||
toCurrency: [
|
||||
{ required: true, message: "目标货币代码不能为空", trigger: "blur" }
|
||||
],
|
||||
rate: [
|
||||
{ required: true, message: "汇率不能为空", trigger: "blur" }
|
||||
],
|
||||
rateDate: [
|
||||
{ required: true, message: "汇率日期不能为空", trigger: "blur" }
|
||||
],
|
||||
}
|
||||
});
|
||||
|
||||
const { queryParams, form, rules } = toRefs(data);
|
||||
|
||||
/** 查询列表 */
|
||||
function getList() {
|
||||
loading.value = true;
|
||||
listExchangerate(queryParams.value).then(response => {
|
||||
exchangerateList.value = response.rows;
|
||||
total.value = response.total;
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
// 取消按钮
|
||||
function cancel() {
|
||||
open.value = false;
|
||||
reset();
|
||||
}
|
||||
|
||||
// 表单重置
|
||||
function reset() {
|
||||
form.value = {
|
||||
id: null,
|
||||
fromCurrency: null,
|
||||
toCurrency: null,
|
||||
rate: null,
|
||||
rateDate: null,
|
||||
source: null,
|
||||
createBy: null,
|
||||
createTime: null,
|
||||
updateBy: null,
|
||||
updateTime: null,
|
||||
remark: null
|
||||
};
|
||||
proxy.resetForm("exchangerateRef");
|
||||
proxy.resetForm("exchangerateDrawerRef");
|
||||
}
|
||||
|
||||
/** 搜索按钮操作 */
|
||||
function handleQuery() {
|
||||
queryParams.value.pageNum = 1;
|
||||
getList();
|
||||
}
|
||||
|
||||
/** 重置按钮操作 */
|
||||
function resetQuery() {
|
||||
proxy.resetForm("queryRef");
|
||||
handleQuery();
|
||||
}
|
||||
|
||||
// 多选框选中数据
|
||||
function handleSelectionChange(selection) {
|
||||
ids.value = selection.map(item => item.id);
|
||||
single.value = selection.length != 1;
|
||||
multiple.value = !selection.length;
|
||||
}
|
||||
|
||||
/** 新增按钮操作 */
|
||||
function handleAdd() {
|
||||
reset();
|
||||
open.value = true;
|
||||
title.value = "添加汇率管理";
|
||||
}
|
||||
|
||||
/** 修改按钮操作 (仅用于弹窗) */
|
||||
function handleUpdate(row) {
|
||||
reset();
|
||||
const _id = row.id || ids.value;
|
||||
getExchangerate(_id).then(response => {
|
||||
form.value = response.data;
|
||||
open.value = true;
|
||||
title.value = "修改汇率管理";
|
||||
});
|
||||
}
|
||||
|
||||
/** 详情按钮操作 */
|
||||
function handleDetail(row) {
|
||||
reset();
|
||||
// 详情前重置表单状态
|
||||
isEditMode.value = false; // 默认进入查看模式
|
||||
const _id = row.id;
|
||||
getExchangerate(_id).then(response => {
|
||||
detailForm.value = response.data;
|
||||
openDetail.value = true;
|
||||
});
|
||||
}
|
||||
|
||||
/** 进入编辑模式 */
|
||||
function handleEnterEditMode() {
|
||||
// 从 detailForm 同步数据到 form,准备编辑
|
||||
const row = detailForm.value;
|
||||
const _id = row.id;
|
||||
|
||||
// 重新获取最新数据以填充表单,保证格式(如checkbox数组)正确
|
||||
getExchangerate(_id).then(response => {
|
||||
form.value = response.data;
|
||||
isEditMode.value = true; // 切换到编辑视图
|
||||
});
|
||||
}
|
||||
|
||||
/** 抽屉内表单提交 */
|
||||
function submitDrawerForm() {
|
||||
proxy.$refs["exchangerateDrawerRef"].validate(valid => {
|
||||
if (valid) {
|
||||
if (form.value.id != null) {
|
||||
updateExchangerate(form.value).then(response => {
|
||||
proxy.$modal.msgSuccess("修改成功");
|
||||
// 修改成功后,刷新详情数据并切回查看模式
|
||||
detailForm.value = JSON.parse(JSON.stringify(form.value));
|
||||
// 注意:如果form数据和详情展示格式有较大差异(如split前后),最好重新调用get详情
|
||||
handleDetail(form.value);
|
||||
getList();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** 详情内删除按钮 */
|
||||
function handleDeleteFromDetail() {
|
||||
const row = detailForm.value;
|
||||
handleDelete(row).then(() => {
|
||||
openDetail.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
/** 常规弹窗提交按钮 */
|
||||
function submitForm() {
|
||||
proxy.$refs["exchangerateRef"].validate(valid => {
|
||||
if (valid) {
|
||||
if (form.value.id != null) {
|
||||
updateExchangerate(form.value).then(response => {
|
||||
proxy.$modal.msgSuccess("修改成功");
|
||||
open.value = false;
|
||||
getList();
|
||||
});
|
||||
} else {
|
||||
addExchangerate(form.value).then(response => {
|
||||
proxy.$modal.msgSuccess("新增成功");
|
||||
open.value = false;
|
||||
getList();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** 删除按钮操作 */
|
||||
function handleDelete(row) {
|
||||
const _ids = row.id || ids.value;
|
||||
return proxy.$modal.confirm('是否确认删除汇率管理编号为"' + _ids + '"的数据项?').then(function() {
|
||||
return delExchangerate(_ids);
|
||||
}).then(() => {
|
||||
getList();
|
||||
proxy.$modal.msgSuccess("删除成功");
|
||||
}).catch(() => {});
|
||||
}
|
||||
|
||||
|
||||
/** 导出按钮操作 */
|
||||
function handleExport() {
|
||||
proxy.download('system/exchangerate/export', {
|
||||
...queryParams.value
|
||||
}, `exchangerate_${new Date().getTime()}.xlsx`)
|
||||
}
|
||||
|
||||
getList();
|
||||
</script>
|
||||
Loading…
Reference in New Issue
Block a user