feat: 火山配置从部门表独立出来,相关取值、缓存、保存重写逻辑
This commit is contained in:
parent
cb72d4edae
commit
8d7cd70cfc
|
|
@ -25,6 +25,23 @@ export function getDept(deptId) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 部门火山引擎配置(解密后明文)
|
||||||
|
export function getDeptArk(deptId) {
|
||||||
|
return request({
|
||||||
|
url: '/system/dept/ark/' + deptId,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存部门火山引擎配置
|
||||||
|
export function updateDeptArk(data) {
|
||||||
|
return request({
|
||||||
|
url: '/system/dept/ark',
|
||||||
|
method: 'put',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 新增部门
|
// 新增部门
|
||||||
export function addDept(data) {
|
export function addDept(data) {
|
||||||
return request({
|
return request({
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,14 @@
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
|
<el-button
|
||||||
|
v-if="isFirstLevelRow(scope.row) || isSecondLevelRow(scope.row)"
|
||||||
|
size="mini"
|
||||||
|
type="text"
|
||||||
|
icon="el-icon-setting"
|
||||||
|
@click="handleArkConfig(scope.row)"
|
||||||
|
v-hasPermi="['system:dept:query', 'system:dept:edit']"
|
||||||
|
>火山配置</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
size="mini"
|
size="mini"
|
||||||
type="text"
|
type="text"
|
||||||
|
|
@ -163,11 +171,21 @@
|
||||||
<p class="model-parm-hint" style="margin: 0; padding-top: 8px"> 限制本部门下「启用」状态账号数量;0 或不填表示不限制。</p>
|
<p class="model-parm-hint" style="margin: 0; padding-top: 8px"> 限制本部门下「启用」状态账号数量;0 或不填表示不限制。</p>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-row v-if="isSecondLevelCompanyForm">
|
</el-form>
|
||||||
|
<div slot="footer" class="dialog-footer">
|
||||||
|
<span v-if="isFirstLevelEditForm" class="form-tip">一级部门仅允许修改名称</span>
|
||||||
|
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||||
|
<el-button @click="cancel">取 消</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<el-dialog title="火山配置" :visible.sync="arkOpen" width="800px" append-to-body @close="resetArkForm">
|
||||||
|
<el-form ref="arkFormRef" :model="arkForm" label-width="120px">
|
||||||
|
<el-row>
|
||||||
<el-col :span="24">
|
<el-col :span="24">
|
||||||
<el-form-item label="Byte API Key">
|
<el-form-item label="Byte API Key">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="form.byteApiKey"
|
v-model="arkForm.byteApiKey"
|
||||||
type="password"
|
type="password"
|
||||||
show-password
|
show-password
|
||||||
placeholder="选填"
|
placeholder="选填"
|
||||||
|
|
@ -176,11 +194,11 @@
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-row v-if="isSecondLevelCompanyForm">
|
<el-row>
|
||||||
<el-col :span="24">
|
<el-col :span="24">
|
||||||
<el-form-item label="火山配置项目">
|
<el-form-item label="火山配置项目">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="form.project"
|
v-model="arkForm.project"
|
||||||
type="password"
|
type="password"
|
||||||
show-password
|
show-password
|
||||||
placeholder="选填"
|
placeholder="选填"
|
||||||
|
|
@ -189,13 +207,13 @@
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-row v-if="isSecondLevelCompanyForm">
|
<el-row>
|
||||||
<el-col :span="24">
|
<el-col :span="24">
|
||||||
<el-form-item label="视频模型">
|
<el-form-item label="视频模型">
|
||||||
<div class="model-parm-block">
|
<div class="model-parm-block">
|
||||||
<div
|
<div
|
||||||
v-for="(row, idx) in modelParamRows"
|
v-for="(row, idx) in arkModelParamRows"
|
||||||
:key="'mp-' + idx"
|
:key="'ark-mp-' + idx"
|
||||||
class="model-parm-row"
|
class="model-parm-row"
|
||||||
>
|
>
|
||||||
<el-input
|
<el-input
|
||||||
|
|
@ -211,13 +229,13 @@
|
||||||
<el-button
|
<el-button
|
||||||
type="text"
|
type="text"
|
||||||
icon="el-icon-delete"
|
icon="el-icon-delete"
|
||||||
:disabled="modelParamRows.length <= 1"
|
:disabled="arkModelParamRows.length <= 1"
|
||||||
@click="removeModelParamRow(idx)"
|
@click="removeArkModelParamRow(idx)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<el-button type="text" icon="el-icon-plus" @click="addModelParamRow">添加模型</el-button>
|
<el-button type="text" icon="el-icon-plus" @click="addArkModelParamRow">添加模型</el-button>
|
||||||
<p class="model-parm-hint">
|
<p class="model-parm-hint">
|
||||||
保存为 JSON 写入 model_parm;门户「视频生成」按用户所属二级部门读取。
|
保存为 JSON 写入 ai_dept_ark_config.model_parm;门户「视频生成」按 ai_user.dept_id 与本部门配置读取。
|
||||||
留空则使用 portal.video.models。
|
留空则使用 portal.video.models。
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -226,9 +244,8 @@
|
||||||
</el-row>
|
</el-row>
|
||||||
</el-form>
|
</el-form>
|
||||||
<div slot="footer" class="dialog-footer">
|
<div slot="footer" class="dialog-footer">
|
||||||
<span v-if="isFirstLevelEditForm" class="form-tip">一级部门仅允许修改名称</span>
|
<el-button type="primary" @click="submitArkForm" v-hasPermi="['system:dept:edit']">确 定</el-button>
|
||||||
<el-button type="primary" @click="submitForm">确 定</el-button>
|
<el-button @click="arkOpen = false">取 消</el-button>
|
||||||
<el-button @click="cancel">取 消</el-button>
|
|
||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -265,7 +282,7 @@
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { listDept, getDept, delDept, addDept, updateDept, listDeptExcludeChild } from "@/api/system/dept"
|
import { listDept, getDept, delDept, addDept, updateDept, listDeptExcludeChild, getDeptArk, updateDeptArk } from "@/api/system/dept"
|
||||||
import Treeselect from "@riophae/vue-treeselect"
|
import Treeselect from "@riophae/vue-treeselect"
|
||||||
import "@riophae/vue-treeselect/dist/vue-treeselect.css"
|
import "@riophae/vue-treeselect/dist/vue-treeselect.css"
|
||||||
|
|
||||||
|
|
@ -287,6 +304,14 @@ export default {
|
||||||
title: "",
|
title: "",
|
||||||
// 是否显示弹出层
|
// 是否显示弹出层
|
||||||
open: false,
|
open: false,
|
||||||
|
arkOpen: false,
|
||||||
|
arkDeptId: null,
|
||||||
|
arkForm: {
|
||||||
|
byteApiKey: undefined,
|
||||||
|
project: undefined,
|
||||||
|
modelParm: undefined
|
||||||
|
},
|
||||||
|
arkModelParamRows: [{ label: '', value: '' }],
|
||||||
// 是否展开,默认全部展开
|
// 是否展开,默认全部展开
|
||||||
isExpandAll: true,
|
isExpandAll: true,
|
||||||
// 重新渲染表格状态
|
// 重新渲染表格状态
|
||||||
|
|
@ -299,7 +324,6 @@ export default {
|
||||||
// 表单参数
|
// 表单参数
|
||||||
form: {},
|
form: {},
|
||||||
originalForm: {},
|
originalForm: {},
|
||||||
modelParamRows: [{ label: '', value: '' }],
|
|
||||||
// 表单校验
|
// 表单校验
|
||||||
rules: {
|
rules: {
|
||||||
parentId: [
|
parentId: [
|
||||||
|
|
@ -332,17 +356,6 @@ export default {
|
||||||
this.getList()
|
this.getList()
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
/** 二级公司:ancestors 为 0,100(即上级为根公司 dept_id=100) */
|
|
||||||
isSecondLevelCompanyForm() {
|
|
||||||
if (this.form.ancestors === "0,100") {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
const pid = this.form.parentId
|
|
||||||
if (pid !== undefined && pid !== null && Number(pid) === 100) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
},
|
|
||||||
isFirstLevelEditForm() {
|
isFirstLevelEditForm() {
|
||||||
return this.form.deptId !== undefined && this.isFirstLevelRow(this.form)
|
return this.form.deptId !== undefined && this.isFirstLevelRow(this.form)
|
||||||
}
|
}
|
||||||
|
|
@ -371,39 +384,78 @@ export default {
|
||||||
return current
|
return current
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
syncModelRowsFromForm() {
|
syncArkModelRowsFromForm() {
|
||||||
this.modelParamRows = [{ label: '', value: '' }]
|
this.arkModelParamRows = [{ label: '', value: '' }]
|
||||||
const raw = this.form.modelParm
|
const raw = this.arkForm.modelParm
|
||||||
if (!raw || String(raw).trim() === '') {
|
if (!raw || String(raw).trim() === '') {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const arr = JSON.parse(raw)
|
const arr = JSON.parse(raw)
|
||||||
if (Array.isArray(arr) && arr.length) {
|
if (Array.isArray(arr) && arr.length) {
|
||||||
this.modelParamRows = arr.map(x => ({
|
this.arkModelParamRows = arr.map(x => ({
|
||||||
label: (x && x.label) ? String(x.label) : '',
|
label: (x && x.label) ? String(x.label) : '',
|
||||||
value: (x && x.value) ? String(x.value) : ''
|
value: (x && x.value) ? String(x.value) : ''
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.modelParamRows = [{ label: '', value: '' }]
|
this.arkModelParamRows = [{ label: '', value: '' }]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
buildModelParmPayload() {
|
buildArkModelParmPayload() {
|
||||||
if (!this.isSecondLevelCompanyForm) {
|
const rows = (this.arkModelParamRows || []).filter(r => r.label && r.value)
|
||||||
|
this.arkForm.modelParm = rows.length ? JSON.stringify(rows) : ''
|
||||||
|
},
|
||||||
|
addArkModelParamRow() {
|
||||||
|
this.arkModelParamRows.push({ label: '', value: '' })
|
||||||
|
},
|
||||||
|
removeArkModelParamRow(idx) {
|
||||||
|
if (this.arkModelParamRows.length <= 1) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const rows = (this.modelParamRows || []).filter(r => r.label && r.value)
|
this.arkModelParamRows.splice(idx, 1)
|
||||||
this.form.modelParm = rows.length ? JSON.stringify(rows) : ''
|
|
||||||
},
|
},
|
||||||
addModelParamRow() {
|
resetArkForm() {
|
||||||
this.modelParamRows.push({ label: '', value: '' })
|
this.arkDeptId = null
|
||||||
|
this.arkForm = {
|
||||||
|
byteApiKey: undefined,
|
||||||
|
project: undefined,
|
||||||
|
modelParm: undefined
|
||||||
|
}
|
||||||
|
this.arkModelParamRows = [{ label: '', value: '' }]
|
||||||
|
if (this.$refs.arkFormRef) {
|
||||||
|
this.$refs.arkFormRef.resetFields()
|
||||||
|
}
|
||||||
},
|
},
|
||||||
removeModelParamRow(idx) {
|
handleArkConfig(row) {
|
||||||
if (this.modelParamRows.length <= 1) {
|
if (!this.isFirstLevelRow(row) && !this.isSecondLevelRow(row)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.modelParamRows.splice(idx, 1)
|
this.arkDeptId = row.deptId
|
||||||
|
getDeptArk(row.deptId).then(response => {
|
||||||
|
const d = response.data || {}
|
||||||
|
this.arkForm = {
|
||||||
|
byteApiKey: d.byteApiKey,
|
||||||
|
project: d.project,
|
||||||
|
modelParm: d.modelParm
|
||||||
|
}
|
||||||
|
this.syncArkModelRowsFromForm()
|
||||||
|
this.arkOpen = true
|
||||||
|
})
|
||||||
|
},
|
||||||
|
submitArkForm() {
|
||||||
|
this.buildArkModelParmPayload()
|
||||||
|
const payload = {
|
||||||
|
deptId: this.arkDeptId,
|
||||||
|
byteApiKey: this.arkForm.byteApiKey !== undefined && this.arkForm.byteApiKey !== null ? this.arkForm.byteApiKey : '',
|
||||||
|
project: this.arkForm.project !== undefined && this.arkForm.project !== null ? this.arkForm.project : '',
|
||||||
|
modelParm: this.arkForm.modelParm !== undefined && this.arkForm.modelParm !== null ? this.arkForm.modelParm : ''
|
||||||
|
}
|
||||||
|
updateDeptArk(payload).then(() => {
|
||||||
|
this.$modal.msgSuccess('保存成功')
|
||||||
|
this.arkOpen = false
|
||||||
|
this.resetArkForm()
|
||||||
|
})
|
||||||
},
|
},
|
||||||
/** 查询部门列表 */
|
/** 查询部门列表 */
|
||||||
getList() {
|
getList() {
|
||||||
|
|
@ -441,13 +493,9 @@ export default {
|
||||||
phone: undefined,
|
phone: undefined,
|
||||||
email: undefined,
|
email: undefined,
|
||||||
maxUserCount: undefined,
|
maxUserCount: undefined,
|
||||||
byteApiKey: undefined,
|
|
||||||
project: undefined,
|
|
||||||
modelParm: undefined,
|
|
||||||
status: "0"
|
status: "0"
|
||||||
}
|
}
|
||||||
this.originalForm = {}
|
this.originalForm = {}
|
||||||
this.modelParamRows = [{ label: '', value: '' }]
|
|
||||||
this.resetForm("form")
|
this.resetForm("form")
|
||||||
},
|
},
|
||||||
/** 搜索按钮操作 */
|
/** 搜索按钮操作 */
|
||||||
|
|
@ -489,7 +537,6 @@ export default {
|
||||||
getDept(row.deptId).then(response => {
|
getDept(row.deptId).then(response => {
|
||||||
this.form = response.data
|
this.form = response.data
|
||||||
this.originalForm = { ...response.data }
|
this.originalForm = { ...response.data }
|
||||||
this.syncModelRowsFromForm()
|
|
||||||
this.open = true
|
this.open = true
|
||||||
this.title = "修改部门"
|
this.title = "修改部门"
|
||||||
listDeptExcludeChild(row.deptId).then(response => {
|
listDeptExcludeChild(row.deptId).then(response => {
|
||||||
|
|
@ -506,7 +553,6 @@ export default {
|
||||||
submitForm: function() {
|
submitForm: function() {
|
||||||
this.$refs["form"].validate(valid => {
|
this.$refs["form"].validate(valid => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
this.buildModelParmPayload()
|
|
||||||
if (this.form.deptId == undefined && !this.deptOptions.some(item => Number(item.deptId) === Number(this.form.parentId))) {
|
if (this.form.deptId == undefined && !this.deptOptions.some(item => Number(item.deptId) === Number(this.form.parentId))) {
|
||||||
this.$modal.msgError("仅允许在一级部门下创建二级部门")
|
this.$modal.msgError("仅允许在一级部门下创建二级部门")
|
||||||
return
|
return
|
||||||
|
|
@ -521,9 +567,6 @@ export default {
|
||||||
this.form.email = oldDept.email
|
this.form.email = oldDept.email
|
||||||
this.form.status = oldDept.status
|
this.form.status = oldDept.status
|
||||||
this.form.maxUserCount = oldDept.maxUserCount
|
this.form.maxUserCount = oldDept.maxUserCount
|
||||||
this.form.byteApiKey = oldDept.byteApiKey
|
|
||||||
this.form.project = oldDept.project
|
|
||||||
this.form.modelParm = oldDept.modelParm
|
|
||||||
}
|
}
|
||||||
updateDept(this.form).then(response => {
|
updateDept(this.form).then(response => {
|
||||||
this.$modal.msgSuccess("修改成功")
|
this.$modal.msgSuccess("修改成功")
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 门户视频生成:按用户二级部门 byte_api_key 调用火山;任务列表含库表与火山过滤列表。
|
* 门户视频生成:按 {@code ai_user.dept_id} 对应 {@code ai_dept_ark_config} 的 API Key 调用火山;任务列表含库表与火山过滤列表。
|
||||||
*/
|
*/
|
||||||
@Api(tags = "门户-视频生成")
|
@Api(tags = "门户-视频生成")
|
||||||
@RestController
|
@RestController
|
||||||
|
|
@ -104,7 +104,7 @@ public class PortalVideoController extends BaseController {
|
||||||
}
|
}
|
||||||
return out.isEmpty() ? null : out;
|
return out.isEmpty() ? null : out;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.warn("解析二级部门 model_parm 失败: {}", e.getMessage());
|
logger.warn("解析部门火山配置 model_parm 失败: {}", e.getMessage());
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,12 +13,15 @@ import org.springframework.web.bind.annotation.PutMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import com.ruoyi.ai.domain.AiDeptArkConfig;
|
||||||
|
import com.ruoyi.ai.service.IAiDeptArkConfigService;
|
||||||
import com.ruoyi.ai.service.IDeptChargeRefundService;
|
import com.ruoyi.ai.service.IDeptChargeRefundService;
|
||||||
import com.ruoyi.common.annotation.Log;
|
import com.ruoyi.common.annotation.Log;
|
||||||
import com.ruoyi.common.constant.UserConstants;
|
import com.ruoyi.common.constant.UserConstants;
|
||||||
import com.ruoyi.common.core.controller.BaseController;
|
import com.ruoyi.common.core.controller.BaseController;
|
||||||
import com.ruoyi.common.core.domain.AjaxResult;
|
import com.ruoyi.common.core.domain.AjaxResult;
|
||||||
import com.ruoyi.common.core.domain.entity.SysDept;
|
import com.ruoyi.common.core.domain.entity.SysDept;
|
||||||
|
import com.ruoyi.common.core.request.system.DeptArkConfigRequest;
|
||||||
import com.ruoyi.common.core.request.system.DeptChargeRefundRequest;
|
import com.ruoyi.common.core.request.system.DeptChargeRefundRequest;
|
||||||
import com.ruoyi.common.core.request.system.DeptPointsCorrectionRequest;
|
import com.ruoyi.common.core.request.system.DeptPointsCorrectionRequest;
|
||||||
import com.ruoyi.common.enums.BusinessType;
|
import com.ruoyi.common.enums.BusinessType;
|
||||||
|
|
@ -40,6 +43,9 @@ public class SysDeptController extends BaseController
|
||||||
@Autowired
|
@Autowired
|
||||||
private IDeptChargeRefundService deptChargeRefundService;
|
private IDeptChargeRefundService deptChargeRefundService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IAiDeptArkConfigService aiDeptArkConfigService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取部门列表
|
* 获取部门列表
|
||||||
*/
|
*/
|
||||||
|
|
@ -74,6 +80,46 @@ public class SysDeptController extends BaseController
|
||||||
return success(deptService.selectDeptById(deptId));
|
return success(deptService.selectDeptById(deptId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部门火山引擎配置(解密后明文,无配置时返回仅含 deptId 的空对象)
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('system:dept:query')")
|
||||||
|
@GetMapping("/ark/{deptId}")
|
||||||
|
public AjaxResult getArk(@PathVariable Long deptId)
|
||||||
|
{
|
||||||
|
deptService.checkDeptDataScope(deptId);
|
||||||
|
if (!deptService.isArkConfigurableDept(deptId))
|
||||||
|
{
|
||||||
|
return error("仅一级或二级部门可配置火山引擎");
|
||||||
|
}
|
||||||
|
AiDeptArkConfig ark = aiDeptArkConfigService.selectDecryptedByDeptId(deptId);
|
||||||
|
if (ark == null)
|
||||||
|
{
|
||||||
|
AiDeptArkConfig empty = new AiDeptArkConfig();
|
||||||
|
empty.setDeptId(deptId);
|
||||||
|
return success(empty);
|
||||||
|
}
|
||||||
|
return success(ark);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存部门火山引擎配置(写入 ai_dept_ark_config)
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('system:dept:edit')")
|
||||||
|
@Log(title = "部门火山配置", businessType = BusinessType.UPDATE)
|
||||||
|
@PutMapping("/ark")
|
||||||
|
public AjaxResult saveArk(@Validated @RequestBody DeptArkConfigRequest request)
|
||||||
|
{
|
||||||
|
Long deptId = request.getDeptId();
|
||||||
|
deptService.checkDeptDataScope(deptId);
|
||||||
|
if (!deptService.isArkConfigurableDept(deptId))
|
||||||
|
{
|
||||||
|
return error("仅一级或二级部门可配置火山引擎");
|
||||||
|
}
|
||||||
|
aiDeptArkConfigService.saveOrUpdateForDept(deptId, request.getByteApiKey(), request.getProject(), request.getModelParm());
|
||||||
|
return success();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 新增部门
|
* 新增部门
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -53,15 +53,6 @@ public class SysDept extends BaseEntity
|
||||||
/** 父部门名称 */
|
/** 父部门名称 */
|
||||||
private String parentName;
|
private String parentName;
|
||||||
|
|
||||||
/** Byte API Key */
|
|
||||||
private String byteApiKey;
|
|
||||||
|
|
||||||
/** 门户视频模型列表 JSON:[{"label":"…","value":"ep-…"},…] */
|
|
||||||
private String modelParm;
|
|
||||||
|
|
||||||
/** Byte project */
|
|
||||||
private String project;
|
|
||||||
|
|
||||||
/** 部门余额 */
|
/** 部门余额 */
|
||||||
private BigDecimal balance;
|
private BigDecimal balance;
|
||||||
|
|
||||||
|
|
@ -187,36 +178,6 @@ public class SysDept extends BaseEntity
|
||||||
this.parentName = parentName;
|
this.parentName = parentName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getByteApiKey()
|
|
||||||
{
|
|
||||||
return byteApiKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setByteApiKey(String byteApiKey)
|
|
||||||
{
|
|
||||||
this.byteApiKey = byteApiKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getModelParm()
|
|
||||||
{
|
|
||||||
return modelParm;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setModelParm(String modelParm)
|
|
||||||
{
|
|
||||||
this.modelParm = modelParm;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getProject()
|
|
||||||
{
|
|
||||||
return project;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setProject(String project)
|
|
||||||
{
|
|
||||||
this.project = project;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BigDecimal getBalance()
|
public BigDecimal getBalance()
|
||||||
{
|
{
|
||||||
return balance;
|
return balance;
|
||||||
|
|
@ -258,9 +219,6 @@ public class SysDept extends BaseEntity
|
||||||
.append("leader", getLeader())
|
.append("leader", getLeader())
|
||||||
.append("phone", getPhone())
|
.append("phone", getPhone())
|
||||||
.append("email", getEmail())
|
.append("email", getEmail())
|
||||||
.append("byteApiKey", getByteApiKey())
|
|
||||||
.append("modelParm", getModelParm())
|
|
||||||
.append("project", getProject())
|
|
||||||
.append("balance", getBalance())
|
.append("balance", getBalance())
|
||||||
.append("maxUserCount", getMaxUserCount())
|
.append("maxUserCount", getMaxUserCount())
|
||||||
.append("status", getStatus())
|
.append("status", getStatus())
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
package com.ruoyi.common.core.request.system;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部门火山引擎配置(保存至 ai_dept_ark_config)
|
||||||
|
*/
|
||||||
|
public class DeptArkConfigRequest {
|
||||||
|
|
||||||
|
@NotNull(message = "部门ID不能为空")
|
||||||
|
private Long deptId;
|
||||||
|
|
||||||
|
/** 明文;空字符串表示清空 */
|
||||||
|
private String byteApiKey;
|
||||||
|
|
||||||
|
/** 明文;空字符串表示清空 */
|
||||||
|
private String project;
|
||||||
|
|
||||||
|
/** 明文 JSON;空字符串表示清空 */
|
||||||
|
private String modelParm;
|
||||||
|
|
||||||
|
public Long getDeptId() {
|
||||||
|
return deptId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeptId(Long deptId) {
|
||||||
|
this.deptId = deptId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getByteApiKey() {
|
||||||
|
return byteApiKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setByteApiKey(String byteApiKey) {
|
||||||
|
this.byteApiKey = byteApiKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getProject() {
|
||||||
|
return project;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProject(String project) {
|
||||||
|
this.project = project;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getModelParm() {
|
||||||
|
return modelParm;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setModelParm(String modelParm) {
|
||||||
|
this.modelParm = modelParm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -23,7 +23,7 @@ public class AiDeptArkConfig extends BaseEntity {
|
||||||
|
|
||||||
/** $column.columnComment */
|
/** $column.columnComment */
|
||||||
@TableId(type = IdType.AUTO)
|
@TableId(type = IdType.AUTO)
|
||||||
private String id;
|
private Long id;
|
||||||
|
|
||||||
/** 部门ID */
|
/** 部门ID */
|
||||||
@Excel(name = "部门ID")
|
@Excel(name = "部门ID")
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,9 @@ public interface AiUserMapper extends BaseMapper<AiUser> {
|
||||||
|
|
||||||
int countAiUserByDeptId(@Param("deptId") Long deptId);
|
int countAiUserByDeptId(@Param("deptId") Long deptId);
|
||||||
|
|
||||||
|
/** 归属指定部门的门户用户主键(用于火山 API Key 缓存失效) */
|
||||||
|
List<Long> selectAiUserIdsByDeptId(@Param("deptId") Long deptId);
|
||||||
|
|
||||||
@Update("update ai_user set dept_id = #{deptId}, update_time = sysdate() where id = #{userId}")
|
@Update("update ai_user set dept_id = #{deptId}, update_time = sysdate() where id = #{userId}")
|
||||||
int updateAiUserDeptId(@Param("userId") Long userId, @Param("deptId") Long deptId);
|
int updateAiUserDeptId(@Param("userId") Long userId, @Param("deptId") Long deptId);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,21 @@ public interface IAiDeptArkConfigService {
|
||||||
*/
|
*/
|
||||||
AiDeptArkConfig selectAiDeptArkConfigById(String id);
|
AiDeptArkConfig selectAiDeptArkConfigById(String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按部门查询火山配置;byte_api_key、project 为解密后的明文(无行返回 null)。
|
||||||
|
*/
|
||||||
|
AiDeptArkConfig selectDecryptedByDeptId(Long deptId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按部门物理删除配置行(无行时返回 0)。
|
||||||
|
*/
|
||||||
|
int deleteByDeptId(Long deptId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存或更新指定部门的火山配置;密文字段按与历史 sys_dept 相同规则加密;落库后使该部门下门户用户的 API Key 缓存失效。
|
||||||
|
*/
|
||||||
|
void saveOrUpdateForDept(Long deptId, String byteApiKey, String project, String modelParm);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询团队(部门)对应火山引擎配置列表
|
* 查询团队(部门)对应火山引擎配置列表
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
package com.ruoyi.ai.service;
|
package com.ruoyi.ai.service;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 门户用户火山方舟 API Key:取自所属二级部门 {@code sys_dept.byte_api_key},带 Redis 缓存。
|
* 门户用户火山方舟 API Key:取自 {@code ai_dept_ark_config}(与 {@code ai_user.dept_id} 对应),带 Redis 缓存。
|
||||||
*/
|
*/
|
||||||
public interface IByteDeptApiKeyService {
|
public interface IByteDeptApiKeyService {
|
||||||
|
|
||||||
|
|
@ -11,13 +11,18 @@ public interface IByteDeptApiKeyService {
|
||||||
String resolveVolcApiKey(Long aiUserId);
|
String resolveVolcApiKey(Long aiUserId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 当前 AI 用户所属二级部门 {@code sys_dept.dept_id}(与 {@link #resolveVolcApiKey(Long)} 中使用的二级节点一致)。
|
* 当前 AI 用户归属部门 {@code ai_user.dept_id}(在仅一级、二级部门树前提下与历史「二级部门」语义对齐;对外方法名保留)。
|
||||||
* 用户未分配部门或部门数据缺失时返回 null。
|
* 用户未分配部门或部门数据缺失时返回 null。
|
||||||
*/
|
*/
|
||||||
Long resolveSecondLevelDeptId(Long aiUserId);
|
Long resolveSecondLevelDeptId(Long aiUserId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 当前用户所属二级部门 {@code sys_dept.model_parm}(JSON 模型列表);未配置或为空时返回 null。
|
* 当前用户归属部门在 {@code ai_dept_ark_config.model_parm} 的 JSON 模型列表;未配置或为空时返回 null。
|
||||||
*/
|
*/
|
||||||
String resolveSecondLevelModelParm(Long aiUserId);
|
String resolveSecondLevelModelParm(Long aiUserId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使 {@code ai_user.dept_id = deptId} 的门户用户的火山 API Key 缓存失效(配置变更或部门删除后调用)。
|
||||||
|
*/
|
||||||
|
void evictVolcApiKeyCacheForDept(Long deptId);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,24 @@
|
||||||
package com.ruoyi.ai.service.impl;
|
package com.ruoyi.ai.service.impl;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.ruoyi.ai.domain.AiDeptArkConfig;
|
||||||
|
import com.ruoyi.ai.mapper.AiDeptArkConfigMapper;
|
||||||
|
import com.ruoyi.ai.mapper.AiUserMapper;
|
||||||
|
import com.ruoyi.ai.service.IAiDeptArkConfigService;
|
||||||
|
import com.ruoyi.common.EncryptionService;
|
||||||
|
import com.ruoyi.common.core.redis.RedisCache;
|
||||||
import com.ruoyi.common.utils.DateUtils;
|
import com.ruoyi.common.utils.DateUtils;
|
||||||
import com.ruoyi.common.utils.SecurityUtils;
|
import com.ruoyi.common.utils.SecurityUtils;
|
||||||
|
import com.ruoyi.common.utils.StringUtils;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import com.ruoyi.ai.mapper.AiDeptArkConfigMapper;
|
|
||||||
import com.ruoyi.ai.domain.AiDeptArkConfig;
|
|
||||||
import com.ruoyi.ai.service.IAiDeptArkConfigService;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 团队(部门)对应火山引擎配置Service业务层处理
|
* 团队(部门)对应火山引擎配置Service业务层处理
|
||||||
|
|
@ -22,92 +29,208 @@ import com.ruoyi.ai.service.IAiDeptArkConfigService;
|
||||||
@Service
|
@Service
|
||||||
public class AiDeptArkConfigServiceImpl implements IAiDeptArkConfigService {
|
public class AiDeptArkConfigServiceImpl implements IAiDeptArkConfigService {
|
||||||
|
|
||||||
|
private static final String BYTE_API_KEY_CACHE_SUFFIX = "_byte_api_key";
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private AiDeptArkConfigMapper aiDeptArkConfigMapper;
|
private AiDeptArkConfigMapper aiDeptArkConfigMapper;
|
||||||
|
|
||||||
/**
|
@Autowired
|
||||||
* 查询团队(部门)对应火山引擎配置
|
private EncryptionService encryptionService;
|
||||||
*
|
|
||||||
* @param id 团队(部门)对应火山引擎配置主键
|
@Autowired
|
||||||
* @return 团队(部门)对应火山引擎配置
|
private RedisCache redisCache;
|
||||||
*/
|
|
||||||
|
@Autowired
|
||||||
|
private AiUserMapper aiUserMapper;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AiDeptArkConfig selectAiDeptArkConfigById(String id) {
|
public AiDeptArkConfig selectAiDeptArkConfigById(String id) {
|
||||||
return aiDeptArkConfigMapper.selectById(id);
|
if (StringUtils.isEmpty(id)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
AiDeptArkConfig row = aiDeptArkConfigMapper.selectById(Long.parseLong(id.trim()));
|
||||||
|
decryptSensitive(row);
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AiDeptArkConfig selectDecryptedByDeptId(Long deptId) {
|
||||||
|
if (deptId == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
AiDeptArkConfig row = aiDeptArkConfigMapper.selectOne(
|
||||||
|
Wrappers.<AiDeptArkConfig>lambdaQuery().eq(AiDeptArkConfig::getDeptId, deptId));
|
||||||
|
decryptSensitive(row);
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int deleteByDeptId(Long deptId) {
|
||||||
|
if (deptId == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int n = aiDeptArkConfigMapper.delete(
|
||||||
|
Wrappers.<AiDeptArkConfig>lambdaQuery().eq(AiDeptArkConfig::getDeptId, deptId));
|
||||||
|
evictVolcApiKeyCacheForDept(deptId);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saveOrUpdateForDept(Long deptId, String byteApiKey, String project, String modelParm) {
|
||||||
|
if (deptId == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String keyPlain = blankToNull(byteApiKey);
|
||||||
|
String projectPlain = blankToNull(project);
|
||||||
|
String modelPlain = blankToNull(modelParm);
|
||||||
|
|
||||||
|
AiDeptArkConfig existing = aiDeptArkConfigMapper.selectOne(
|
||||||
|
Wrappers.<AiDeptArkConfig>lambdaQuery().eq(AiDeptArkConfig::getDeptId, deptId));
|
||||||
|
if (existing == null) {
|
||||||
|
AiDeptArkConfig row = new AiDeptArkConfig();
|
||||||
|
row.setDeptId(deptId);
|
||||||
|
row.setByteApiKey(encodeNullable(keyPlain));
|
||||||
|
row.setProject(encodeNullable(projectPlain));
|
||||||
|
row.setModelParm(modelPlain);
|
||||||
|
row.setCreateBy(SecurityUtils.getUsername());
|
||||||
|
row.setCreateTime(DateUtils.getNowDate());
|
||||||
|
aiDeptArkConfigMapper.insert(row);
|
||||||
|
} else {
|
||||||
|
existing.setByteApiKey(encodeNullable(keyPlain));
|
||||||
|
existing.setProject(encodeNullable(projectPlain));
|
||||||
|
existing.setModelParm(modelPlain);
|
||||||
|
existing.setUpdateBy(SecurityUtils.getUsername());
|
||||||
|
existing.setUpdateTime(DateUtils.getNowDate());
|
||||||
|
aiDeptArkConfigMapper.updateById(existing);
|
||||||
|
}
|
||||||
|
evictVolcApiKeyCacheForDept(deptId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String blankToNull(String s) {
|
||||||
|
if (s == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String t = s.trim();
|
||||||
|
return t.isEmpty() ? null : t;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String encodeNullable(String plain) {
|
||||||
|
if (plain == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return encryptionService.encode(plain);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void decryptSensitive(AiDeptArkConfig row) {
|
||||||
|
if (row == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (StringUtils.isNotEmpty(row.getByteApiKey())) {
|
||||||
|
row.setByteApiKey(encryptionService.decode(row.getByteApiKey()));
|
||||||
|
}
|
||||||
|
if (StringUtils.isNotEmpty(row.getProject())) {
|
||||||
|
row.setProject(encryptionService.decode(row.getProject()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void encryptSensitiveForStore(AiDeptArkConfig row) {
|
||||||
|
if (row == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (StringUtils.isNotEmpty(row.getByteApiKey())) {
|
||||||
|
row.setByteApiKey(encryptionService.encode(row.getByteApiKey()));
|
||||||
|
}
|
||||||
|
if (StringUtils.isNotEmpty(row.getProject())) {
|
||||||
|
row.setProject(encryptionService.encode(row.getProject()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void evictVolcApiKeyCacheForDept(Long deptId) {
|
||||||
|
List<Long> userIds = aiUserMapper.selectAiUserIdsByDeptId(deptId);
|
||||||
|
if (userIds == null || userIds.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (Long uid : userIds) {
|
||||||
|
if (uid != null) {
|
||||||
|
redisCache.deleteObject(uid + BYTE_API_KEY_CACHE_SUFFIX);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询团队(部门)对应火山引擎配置列表
|
|
||||||
*
|
|
||||||
* @param aiDeptArkConfig 团队(部门)对应火山引擎配置
|
|
||||||
* @return 团队(部门)对应火山引擎配置
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public List<AiDeptArkConfig> selectAiDeptArkConfigList(AiDeptArkConfig aiDeptArkConfig) {
|
public List<AiDeptArkConfig> selectAiDeptArkConfigList(AiDeptArkConfig aiDeptArkConfig) {
|
||||||
LambdaQueryWrapper<AiDeptArkConfig> query = Wrappers.lambdaQuery(aiDeptArkConfig);
|
LambdaQueryWrapper<AiDeptArkConfig> query = Wrappers.lambdaQuery(aiDeptArkConfig);
|
||||||
query.orderByDesc(AiDeptArkConfig::getId);
|
query.orderByDesc(AiDeptArkConfig::getId);
|
||||||
return aiDeptArkConfigMapper.selectList(query);
|
List<AiDeptArkConfig> list = aiDeptArkConfigMapper.selectList(query);
|
||||||
|
for (AiDeptArkConfig row : list) {
|
||||||
|
decryptSensitive(row);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 分页查询团队(部门)对应火山引擎配置列表
|
|
||||||
*
|
|
||||||
* @param aiDeptArkConfig 团队(部门)对应火山引擎配置
|
|
||||||
* @return 团队(部门)对应火山引擎配置
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public IPage<AiDeptArkConfig> selectAiDeptArkConfigPage(Page page, AiDeptArkConfig aiDeptArkConfig) {
|
public IPage<AiDeptArkConfig> selectAiDeptArkConfigPage(Page page, AiDeptArkConfig aiDeptArkConfig) {
|
||||||
LambdaQueryWrapper<AiDeptArkConfig> query = Wrappers.lambdaQuery(aiDeptArkConfig);
|
LambdaQueryWrapper<AiDeptArkConfig> query = Wrappers.lambdaQuery(aiDeptArkConfig);
|
||||||
return aiDeptArkConfigMapper.selectPage(page, query);
|
IPage<AiDeptArkConfig> result = aiDeptArkConfigMapper.selectPage(page, query);
|
||||||
|
for (AiDeptArkConfig row : result.getRecords()) {
|
||||||
|
decryptSensitive(row);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 新增团队(部门)对应火山引擎配置
|
|
||||||
*
|
|
||||||
* @param aiDeptArkConfig 团队(部门)对应火山引擎配置
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public int insertAiDeptArkConfig(AiDeptArkConfig aiDeptArkConfig) {
|
public int insertAiDeptArkConfig(AiDeptArkConfig aiDeptArkConfig) {
|
||||||
|
encryptSensitiveForStore(aiDeptArkConfig);
|
||||||
aiDeptArkConfig.setCreateBy(SecurityUtils.getUsername());
|
aiDeptArkConfig.setCreateBy(SecurityUtils.getUsername());
|
||||||
aiDeptArkConfig.setCreateTime(DateUtils.getNowDate());
|
aiDeptArkConfig.setCreateTime(DateUtils.getNowDate());
|
||||||
return aiDeptArkConfigMapper.insert(aiDeptArkConfig);
|
int r = aiDeptArkConfigMapper.insert(aiDeptArkConfig);
|
||||||
|
if (r > 0 && aiDeptArkConfig.getDeptId() != null) {
|
||||||
|
evictVolcApiKeyCacheForDept(aiDeptArkConfig.getDeptId());
|
||||||
|
}
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 修改团队(部门)对应火山引擎配置
|
|
||||||
*
|
|
||||||
* @param aiDeptArkConfig 团队(部门)对应火山引擎配置
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public int updateAiDeptArkConfig(AiDeptArkConfig aiDeptArkConfig) {
|
public int updateAiDeptArkConfig(AiDeptArkConfig aiDeptArkConfig) {
|
||||||
|
encryptSensitiveForStore(aiDeptArkConfig);
|
||||||
aiDeptArkConfig.setUpdateBy(SecurityUtils.getUsername());
|
aiDeptArkConfig.setUpdateBy(SecurityUtils.getUsername());
|
||||||
aiDeptArkConfig.setUpdateTime(DateUtils.getNowDate());
|
aiDeptArkConfig.setUpdateTime(DateUtils.getNowDate());
|
||||||
return aiDeptArkConfigMapper.updateById(aiDeptArkConfig);
|
int r = aiDeptArkConfigMapper.updateById(aiDeptArkConfig);
|
||||||
|
if (r > 0 && aiDeptArkConfig.getDeptId() != null) {
|
||||||
|
evictVolcApiKeyCacheForDept(aiDeptArkConfig.getDeptId());
|
||||||
|
}
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 批量删除团队(部门)对应火山引擎配置
|
|
||||||
*
|
|
||||||
* @param ids 需要删除的团队(部门)对应火山引擎配置主键
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public int deleteAiDeptArkConfigByIds(String[] ids)
|
public int deleteAiDeptArkConfigByIds(String[] ids) {
|
||||||
{
|
if (ids == null || ids.length == 0) {
|
||||||
return aiDeptArkConfigMapper.deleteBatchIds(java.util.Arrays.asList(ids));
|
return 0;
|
||||||
|
}
|
||||||
|
List<Long> longIds = Arrays.stream(ids).map(String::trim).filter(StringUtils::isNotEmpty)
|
||||||
|
.map(Long::parseLong).collect(Collectors.toList());
|
||||||
|
List<AiDeptArkConfig> rows = aiDeptArkConfigMapper.selectBatchIds(longIds);
|
||||||
|
int n = aiDeptArkConfigMapper.deleteBatchIds(longIds);
|
||||||
|
if (n > 0) {
|
||||||
|
for (AiDeptArkConfig row : rows) {
|
||||||
|
if (row != null && row.getDeptId() != null) {
|
||||||
|
evictVolcApiKeyCacheForDept(row.getDeptId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除团队(部门)对应火山引擎配置信息
|
|
||||||
*
|
|
||||||
* @param id 团队(部门)对应火山引擎配置主键
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public int deleteAiDeptArkConfigById(String id)
|
public int deleteAiDeptArkConfigById(String id) {
|
||||||
{
|
if (StringUtils.isEmpty(id)) {
|
||||||
return aiDeptArkConfigMapper.deleteById(id);
|
return 0;
|
||||||
|
}
|
||||||
|
AiDeptArkConfig row = aiDeptArkConfigMapper.selectById(Long.parseLong(id.trim()));
|
||||||
|
int n = aiDeptArkConfigMapper.deleteById(Long.parseLong(id.trim()));
|
||||||
|
if (n > 0 && row != null && row.getDeptId() != null) {
|
||||||
|
evictVolcApiKeyCacheForDept(row.getDeptId());
|
||||||
|
}
|
||||||
|
return n;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,13 @@ package com.ruoyi.ai.service.impl;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
import com.fasterxml.jackson.databind.*;
|
import com.fasterxml.jackson.databind.*;
|
||||||
|
import com.ruoyi.ai.domain.AiDeptArkConfig;
|
||||||
import com.ruoyi.ai.mapper.AiUserMapper;
|
import com.ruoyi.ai.mapper.AiUserMapper;
|
||||||
import com.ruoyi.common.EncryptionService;
|
import com.ruoyi.ai.service.IAiDeptArkConfigService;
|
||||||
import com.ruoyi.common.core.domain.entity.AiUser;
|
import com.ruoyi.common.core.domain.entity.AiUser;
|
||||||
import com.ruoyi.common.core.domain.entity.SysDept;
|
|
||||||
import com.ruoyi.common.utils.SecurityUtils;
|
import com.ruoyi.common.utils.SecurityUtils;
|
||||||
|
import com.ruoyi.common.utils.StringUtils;
|
||||||
import com.ruoyi.common.utils.http.OkHttpUtils;
|
import com.ruoyi.common.utils.http.OkHttpUtils;
|
||||||
import com.ruoyi.system.mapper.SysDeptMapper;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import okhttp3.*;
|
import okhttp3.*;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
|
@ -34,10 +34,7 @@ public class BaseByteApiService {
|
||||||
@Resource
|
@Resource
|
||||||
private AiUserMapper userMapper;
|
private AiUserMapper userMapper;
|
||||||
@Resource
|
@Resource
|
||||||
private SysDeptMapper deptMapper;
|
private IAiDeptArkConfigService aiDeptArkConfigService;
|
||||||
@Resource
|
|
||||||
private EncryptionService encryptionService;
|
|
||||||
protected String DEPT_ANCESTORS_SPLIT = ",";
|
|
||||||
@Value("${volcengine.ak}")
|
@Value("${volcengine.ak}")
|
||||||
protected String accessKeyId;
|
protected String accessKeyId;
|
||||||
@Value("${volcengine.sk}")
|
@Value("${volcengine.sk}")
|
||||||
|
|
@ -70,7 +67,7 @@ public class BaseByteApiService {
|
||||||
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据用户找到对应的project
|
* 根据门户用户 {@code ai_user.dept_id} 对应 {@link AiDeptArkConfig#getProject()}(解密后)解析 project。
|
||||||
*/
|
*/
|
||||||
protected String getUserProject() {
|
protected String getUserProject() {
|
||||||
Long userId = SecurityUtils.getAiUserId();
|
Long userId = SecurityUtils.getAiUserId();
|
||||||
|
|
@ -78,39 +75,14 @@ public class BaseByteApiService {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
AiUser user = userMapper.selectAiUserById(userId);
|
AiUser user = userMapper.selectAiUserById(userId);
|
||||||
if (user == null) {
|
if (user == null || user.getDeptId() == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
// 第二层部门ID,API_KEY放在这里
|
AiDeptArkConfig ark = aiDeptArkConfigService.selectDecryptedByDeptId(user.getDeptId());
|
||||||
Long secondLvDeptId = getSecondLevelDept(user.getDeptId());
|
if (ark == null || StringUtils.isEmpty(ark.getProject())) {
|
||||||
if (secondLvDeptId == null) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
SysDept secondDept = deptMapper.selectDeptById(secondLvDeptId);
|
return ark.getProject().trim();
|
||||||
return encryptionService.decode(secondDept.getProject());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 找到当前部门所属第二部门ID
|
|
||||||
*
|
|
||||||
* @param deptId 当前部门
|
|
||||||
*/
|
|
||||||
protected Long getSecondLevelDept(long deptId) {
|
|
||||||
SysDept dept = deptMapper.selectDeptById(deptId);
|
|
||||||
String ancestors = dept.getAncestors();
|
|
||||||
// 判断是第几层
|
|
||||||
if (ancestors == null || ancestors.isEmpty() || "0".equals(ancestors)) {
|
|
||||||
// 第一层
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
String[] parentDeptArray = ancestors.split(DEPT_ANCESTORS_SPLIT);
|
|
||||||
int length = parentDeptArray.length;
|
|
||||||
if (length == 2) {
|
|
||||||
// 只有一个上级,所以当前节点是第二层,直接返回
|
|
||||||
return deptId;
|
|
||||||
}
|
|
||||||
// 大于二级
|
|
||||||
return Long.parseLong(parentDeptArray[2]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public <R> R callApi(String action, Object request, Class<R> responseClass) throws IOException {
|
public <R> R callApi(String action, Object request, Class<R> responseClass) throws IOException {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
package com.ruoyi.ai.service.impl;
|
package com.ruoyi.ai.service.impl;
|
||||||
|
|
||||||
|
import com.ruoyi.ai.domain.AiDeptArkConfig;
|
||||||
|
import com.ruoyi.ai.mapper.AiUserMapper;
|
||||||
|
import com.ruoyi.ai.service.IAiDeptArkConfigService;
|
||||||
import com.ruoyi.ai.service.IAiUserService;
|
import com.ruoyi.ai.service.IAiUserService;
|
||||||
import com.ruoyi.ai.service.IByteDeptApiKeyService;
|
import com.ruoyi.ai.service.IByteDeptApiKeyService;
|
||||||
import com.ruoyi.common.EncryptionService;
|
import com.ruoyi.common.EncryptionService;
|
||||||
|
|
@ -14,19 +17,22 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
import java.util.List;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
public class ByteDeptApiKeyServiceImpl implements IByteDeptApiKeyService {
|
public class ByteDeptApiKeyServiceImpl implements IByteDeptApiKeyService {
|
||||||
|
|
||||||
@Resource
|
private static final String BYTE_API_KEY_CACHE_SUFFIX = "_byte_api_key";
|
||||||
private EncryptionService encryptionService;
|
|
||||||
private static final String NO_DEPT_MSG = "用户未分配部门:请在后台为门户用户设置 ai_user.dept_id(关联 sys_dept.dept_id)";
|
private static final String NO_DEPT_MSG = "用户未分配部门:请在后台为门户用户设置 ai_user.dept_id(关联 sys_dept.dept_id)";
|
||||||
private static final String NO_DEPT_ROW_MSG = "用户所属部门不存在或已删除,请核对 ai_user.dept_id";
|
private static final String NO_DEPT_ROW_MSG = "用户所属部门不存在或已删除,请核对 ai_user.dept_id";
|
||||||
private static final String NO_API_KEY_MSG = "部门未配置火山 API Key:请在 sys_dept 为用户所在部门(或其上级二级部门)配置 byte_api_key";
|
private static final String NO_API_KEY_MSG = "部门未配置火山 API Key:请在后台「部门管理」中为该部门配置火山 API Key(ai_dept_ark_config)";
|
||||||
private static final int CACHE_HOURS = 1;
|
private static final int CACHE_HOURS = 1;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private EncryptionService encryptionService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private RedisCache redisCache;
|
private RedisCache redisCache;
|
||||||
|
|
||||||
|
|
@ -36,15 +42,20 @@ public class ByteDeptApiKeyServiceImpl implements IByteDeptApiKeyService {
|
||||||
@Autowired
|
@Autowired
|
||||||
private ISysDeptService sysDeptService;
|
private ISysDeptService sysDeptService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IAiDeptArkConfigService aiDeptArkConfigService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private AiUserMapper aiUserMapper;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String resolveVolcApiKey(Long aiUserId) {
|
public String resolveVolcApiKey(Long aiUserId) {
|
||||||
if (aiUserId == null) {
|
if (aiUserId == null) {
|
||||||
throw new ServiceException(NO_DEPT_MSG);
|
throw new ServiceException(NO_DEPT_MSG);
|
||||||
}
|
}
|
||||||
String cacheKey = aiUserId + "_byte_api_key";
|
String cacheKey = aiUserId + BYTE_API_KEY_CACHE_SUFFIX;
|
||||||
String cached = redisCache.getCacheObject(cacheKey);
|
String cached = redisCache.getCacheObject(cacheKey);
|
||||||
if (StringUtils.isNotEmpty(cached)) {
|
if (StringUtils.isNotEmpty(cached)) {
|
||||||
// 解密:缓存保存加密后的字符串比较安全
|
|
||||||
return encryptionService.decode(cached);
|
return encryptionService.decode(cached);
|
||||||
}
|
}
|
||||||
AiUser aiUser = aiUserService.selectAiUserById(aiUserId);
|
AiUser aiUser = aiUserService.selectAiUserById(aiUserId);
|
||||||
|
|
@ -55,21 +66,11 @@ public class ByteDeptApiKeyServiceImpl implements IByteDeptApiKeyService {
|
||||||
if (userDept == null) {
|
if (userDept == null) {
|
||||||
throw new ServiceException(NO_DEPT_ROW_MSG);
|
throw new ServiceException(NO_DEPT_ROW_MSG);
|
||||||
}
|
}
|
||||||
// 优先使用用户直接归属部门的 Key;多数业务把用户挂在分公司(如 101)并在该节点配 byte_api_key
|
AiDeptArkConfig ark = aiDeptArkConfigService.selectDecryptedByDeptId(aiUser.getDeptId());
|
||||||
String apiKey = trimKey(userDept.getByteApiKey());
|
String apiKey = ark != null ? trimKey(ark.getByteApiKey()) : null;
|
||||||
if (StringUtils.isEmpty(apiKey)) {
|
|
||||||
Long fallbackDeptId = secondLevelDeptIdFrom(userDept);
|
|
||||||
if (!fallbackDeptId.equals(userDept.getDeptId())) {
|
|
||||||
SysDept keyDept = sysDeptService.selectDeptById(fallbackDeptId);
|
|
||||||
if (keyDept != null) {
|
|
||||||
apiKey = trimKey(keyDept.getByteApiKey());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (StringUtils.isEmpty(apiKey)) {
|
if (StringUtils.isEmpty(apiKey)) {
|
||||||
throw new ServiceException(NO_API_KEY_MSG);
|
throw new ServiceException(NO_API_KEY_MSG);
|
||||||
}
|
}
|
||||||
// 缓存中保存加密值
|
|
||||||
String encodeApiKey = encryptionService.encode(apiKey);
|
String encodeApiKey = encryptionService.encode(apiKey);
|
||||||
redisCache.setCacheObject(cacheKey, encodeApiKey, CACHE_HOURS, TimeUnit.HOURS);
|
redisCache.setCacheObject(cacheKey, encodeApiKey, CACHE_HOURS, TimeUnit.HOURS);
|
||||||
return apiKey;
|
return apiKey;
|
||||||
|
|
@ -84,59 +85,46 @@ public class ByteDeptApiKeyServiceImpl implements IByteDeptApiKeyService {
|
||||||
if (aiUser == null || aiUser.getDeptId() == null) {
|
if (aiUser == null || aiUser.getDeptId() == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
SysDept userDept = sysDeptService.selectDeptById(aiUser.getDeptId());
|
return aiUser.getDeptId();
|
||||||
if (userDept == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return secondLevelDeptIdFrom(userDept);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String resolveSecondLevelModelParm(Long aiUserId) {
|
public String resolveSecondLevelModelParm(Long aiUserId) {
|
||||||
Long secondId = resolveSecondLevelDeptId(aiUserId);
|
if (aiUserId == null) {
|
||||||
if (secondId == null) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
SysDept second = sysDeptService.selectDeptById(secondId);
|
AiUser aiUser = aiUserService.selectAiUserById(aiUserId);
|
||||||
if (second == null) {
|
if (aiUser == null || aiUser.getDeptId() == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
String raw = second.getModelParm();
|
AiDeptArkConfig ark = aiDeptArkConfigService.selectDecryptedByDeptId(aiUser.getDeptId());
|
||||||
|
if (ark == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String raw = ark.getModelParm();
|
||||||
if (StringUtils.isEmpty(raw)) {
|
if (StringUtils.isEmpty(raw)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return raw.trim();
|
return raw.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void evictVolcApiKeyCacheForDept(Long deptId) {
|
||||||
|
if (deptId == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
List<Long> userIds = aiUserMapper.selectAiUserIdsByDeptId(deptId);
|
||||||
|
if (userIds == null || userIds.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (Long uid : userIds) {
|
||||||
|
if (uid != null) {
|
||||||
|
redisCache.deleteObject(uid + BYTE_API_KEY_CACHE_SUFFIX);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static String trimKey(String raw) {
|
private static String trimKey(String raw) {
|
||||||
return raw == null ? null : raw.trim();
|
return raw == null ? null : raw.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 二级部门:祖级路径中,紧接在「一级」(ancestors 第二段)之下的部门节点;
|
|
||||||
* 深度不足时退回用户当前部门。
|
|
||||||
*/
|
|
||||||
private Long secondLevelDeptIdFrom(SysDept userDept) {
|
|
||||||
String ancestors = userDept.getAncestors();
|
|
||||||
if (StringUtils.isEmpty(ancestors)) {
|
|
||||||
return userDept.getDeptId();
|
|
||||||
}
|
|
||||||
String[] parts = ancestors.split(",");
|
|
||||||
if (parts.length >= 3) {
|
|
||||||
try {
|
|
||||||
return Long.parseLong(parts[2].trim());
|
|
||||||
} catch (NumberFormatException ignored) {
|
|
||||||
return userDept.getDeptId();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (parts.length == 2) {
|
|
||||||
try {
|
|
||||||
// return Long.parseLong(parts[1].trim());
|
|
||||||
return userDept.getDeptId();
|
|
||||||
} catch (NumberFormatException ignored) {
|
|
||||||
return userDept.getDeptId();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return userDept.getDeptId();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -144,4 +144,9 @@ public interface ISysDeptService
|
||||||
* 积分更正:更新部门余额并写入集团流水(手动修改类型),不产生充值/退款订单。
|
* 积分更正:更新部门余额并写入集团流水(手动修改类型),不产生充值/退款订单。
|
||||||
*/
|
*/
|
||||||
void editScore(DeptPointsCorrectionRequest request);
|
void editScore(DeptPointsCorrectionRequest request);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否允许配置火山引擎(一级或二级部门;与仅两级部门树一致)。
|
||||||
|
*/
|
||||||
|
boolean isArkConfigurableDept(Long deptId);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,8 @@ import java.util.Objects;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import com.ruoyi.ai.domain.AiGroupBalanceChangeRecord;
|
import com.ruoyi.ai.domain.AiGroupBalanceChangeRecord;
|
||||||
|
import com.ruoyi.ai.service.IAiDeptArkConfigService;
|
||||||
import com.ruoyi.ai.service.IAiGroupBalanceChangeRecordService;
|
import com.ruoyi.ai.service.IAiGroupBalanceChangeRecordService;
|
||||||
import com.ruoyi.common.EncryptionService;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
@ -33,8 +33,6 @@ import com.ruoyi.system.mapper.SysRoleMapper;
|
||||||
import com.ruoyi.system.mapper.SysUserMapper;
|
import com.ruoyi.system.mapper.SysUserMapper;
|
||||||
import com.ruoyi.system.service.ISysDeptService;
|
import com.ruoyi.system.service.ISysDeptService;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 部门管理 服务实现
|
* 部门管理 服务实现
|
||||||
*
|
*
|
||||||
|
|
@ -52,12 +50,12 @@ public class SysDeptServiceImpl implements ISysDeptService
|
||||||
@Autowired
|
@Autowired
|
||||||
private SysUserMapper userMapper;
|
private SysUserMapper userMapper;
|
||||||
|
|
||||||
@Resource
|
|
||||||
private EncryptionService encryptionService;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IAiGroupBalanceChangeRecordService aiGroupBalanceChangeRecordService;
|
private IAiGroupBalanceChangeRecordService aiGroupBalanceChangeRecordService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IAiDeptArkConfigService aiDeptArkConfigService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询部门管理数据
|
* 查询部门管理数据
|
||||||
*
|
*
|
||||||
|
|
@ -146,14 +144,7 @@ public class SysDeptServiceImpl implements ISysDeptService
|
||||||
@Override
|
@Override
|
||||||
public SysDept selectDeptById(Long deptId)
|
public SysDept selectDeptById(Long deptId)
|
||||||
{
|
{
|
||||||
SysDept sysDept = deptMapper.selectDeptById(deptId);
|
return deptMapper.selectDeptById(deptId);
|
||||||
if (sysDept.getByteApiKey() != null && !sysDept.getByteApiKey().isEmpty()) {
|
|
||||||
sysDept.setByteApiKey(encryptionService.decode(sysDept.getByteApiKey()));
|
|
||||||
}
|
|
||||||
if (sysDept.getProject() != null && !sysDept.getProject().isEmpty()) {
|
|
||||||
sysDept.setProject(encryptionService.decode(sysDept.getProject()));
|
|
||||||
}
|
|
||||||
return sysDept;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -252,12 +243,6 @@ public class SysDeptServiceImpl implements ISysDeptService
|
||||||
throw new ServiceException("部门停用,不允许新增");
|
throw new ServiceException("部门停用,不允许新增");
|
||||||
}
|
}
|
||||||
dept.setAncestors(info.getAncestors() + "," + dept.getParentId());
|
dept.setAncestors(info.getAncestors() + "," + dept.getParentId());
|
||||||
if (StringUtils.isNotEmpty(dept.getByteApiKey())) {
|
|
||||||
dept.setByteApiKey(encryptionService.encode(dept.getByteApiKey()));
|
|
||||||
}
|
|
||||||
if (StringUtils.isNotEmpty(dept.getProject())) {
|
|
||||||
dept.setProject(encryptionService.encode(dept.getProject()));
|
|
||||||
}
|
|
||||||
return deptMapper.insertDept(dept);
|
return deptMapper.insertDept(dept);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -285,12 +270,6 @@ public class SysDeptServiceImpl implements ISysDeptService
|
||||||
dept.setAncestors(newAncestors);
|
dept.setAncestors(newAncestors);
|
||||||
updateDeptChildren(dept.getDeptId(), newAncestors, oldAncestors);
|
updateDeptChildren(dept.getDeptId(), newAncestors, oldAncestors);
|
||||||
}
|
}
|
||||||
if (StringUtils.isNotEmpty(dept.getByteApiKey())) {
|
|
||||||
dept.setByteApiKey(encryptionService.encode(dept.getByteApiKey()));
|
|
||||||
}
|
|
||||||
if (StringUtils.isNotEmpty(dept.getProject())) {
|
|
||||||
dept.setProject(encryptionService.encode(dept.getProject()));
|
|
||||||
}
|
|
||||||
int result = deptMapper.updateDept(dept);
|
int result = deptMapper.updateDept(dept);
|
||||||
if (UserConstants.DEPT_NORMAL.equals(dept.getStatus()) && StringUtils.isNotEmpty(dept.getAncestors())
|
if (UserConstants.DEPT_NORMAL.equals(dept.getStatus()) && StringUtils.isNotEmpty(dept.getAncestors())
|
||||||
&& !StringUtils.equals("0", dept.getAncestors()))
|
&& !StringUtils.equals("0", dept.getAncestors()))
|
||||||
|
|
@ -357,9 +336,30 @@ public class SysDeptServiceImpl implements ISysDeptService
|
||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public int deleteDeptById(Long deptId)
|
public int deleteDeptById(Long deptId)
|
||||||
{
|
{
|
||||||
return deptMapper.deleteDeptById(deptId);
|
int rows = deptMapper.deleteDeptById(deptId);
|
||||||
|
if (rows > 0)
|
||||||
|
{
|
||||||
|
aiDeptArkConfigService.deleteByDeptId(deptId);
|
||||||
|
}
|
||||||
|
return rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isArkConfigurableDept(Long deptId)
|
||||||
|
{
|
||||||
|
if (deptId == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
SysDept d = deptMapper.selectDeptById(deptId);
|
||||||
|
if (d == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return isFirstLevelDept(d) || isSecondLevelDept(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -518,9 +518,6 @@ public class SysDeptServiceImpl implements ISysDeptService
|
||||||
throw new ServiceException("一级部门仅允许修改名称");
|
throw new ServiceException("一级部门仅允许修改名称");
|
||||||
}
|
}
|
||||||
newDept.setAncestors(oldDept.getAncestors());
|
newDept.setAncestors(oldDept.getAncestors());
|
||||||
newDept.setByteApiKey(oldDept.getByteApiKey());
|
|
||||||
newDept.setProject(oldDept.getProject());
|
|
||||||
newDept.setModelParm(oldDept.getModelParm());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -86,6 +86,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
<select id="countAiUserByDeptId" resultType="int">
|
<select id="countAiUserByDeptId" resultType="int">
|
||||||
select count(1) from ai_user where del_flag = '0' and dept_id = #{deptId}
|
select count(1) from ai_user where del_flag = '0' and dept_id = #{deptId}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="selectAiUserIdsByDeptId" resultType="java.lang.Long">
|
||||||
|
select id from ai_user where del_flag = '0' and dept_id = #{deptId}
|
||||||
|
</select>
|
||||||
<select id="selectPasswordById" resultType="java.lang.String">
|
<select id="selectPasswordById" resultType="java.lang.String">
|
||||||
select password from ai_user where id = #{id}
|
select password from ai_user where id = #{id}
|
||||||
</select>
|
</select>
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
<result property="leader" column="leader" />
|
<result property="leader" column="leader" />
|
||||||
<result property="phone" column="phone" />
|
<result property="phone" column="phone" />
|
||||||
<result property="email" column="email" />
|
<result property="email" column="email" />
|
||||||
<result property="byteApiKey" column="byte_api_key" />
|
|
||||||
<result property="modelParm" column="model_parm" />
|
|
||||||
<result property="status" column="status" />
|
<result property="status" column="status" />
|
||||||
<result property="delFlag" column="del_flag" />
|
<result property="delFlag" column="del_flag" />
|
||||||
<result property="parentName" column="parent_name" />
|
<result property="parentName" column="parent_name" />
|
||||||
|
|
@ -28,7 +26,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
</resultMap>
|
</resultMap>
|
||||||
|
|
||||||
<sql id="selectDeptVo">
|
<sql id="selectDeptVo">
|
||||||
select d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.phone, d.email, d.byte_api_key, d.status, d.del_flag, d.create_by, d.create_time, d.project, d.balance, d.max_user_count
|
select d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.phone, d.email, d.status, d.del_flag, d.create_by, d.create_time, d.balance, d.max_user_count
|
||||||
from sys_dept d
|
from sys_dept d
|
||||||
</sql>
|
</sql>
|
||||||
|
|
||||||
|
|
@ -64,7 +62,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="selectDeptById" parameterType="Long" resultMap="SysDeptResult">
|
<select id="selectDeptById" parameterType="Long" resultMap="SysDeptResult">
|
||||||
select d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.phone, d.email, d.byte_api_key, d.model_parm, d.status, d.project, d.balance, d.max_user_count,
|
select d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.phone, d.email, d.status, d.balance, d.max_user_count,
|
||||||
(select dept_name from sys_dept where dept_id = d.parent_id) parent_name
|
(select dept_name from sys_dept where dept_id = d.parent_id) parent_name
|
||||||
from sys_dept d
|
from sys_dept d
|
||||||
where d.dept_id = #{deptId}
|
where d.dept_id = #{deptId}
|
||||||
|
|
@ -79,8 +77,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
where del_flag = '0' and parent_id = #{deptId} limit 1
|
where del_flag = '0' and parent_id = #{deptId} limit 1
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="selectChildrenDeptById" parameterType="Long" resultMap="SysDeptResult">
|
<select id="selectChildrenDeptById" parameterType="Long" resultMap="SysDeptResult">
|
||||||
select * from sys_dept where find_in_set(#{deptId}, ancestors)
|
select d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.phone, d.email, d.status, d.del_flag, d.create_by, d.create_time, d.update_by, d.update_time, d.balance, d.max_user_count
|
||||||
|
from sys_dept d where find_in_set(#{deptId}, d.ancestors)
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="selectNormalChildrenDeptById" parameterType="Long" resultType="int">
|
<select id="selectNormalChildrenDeptById" parameterType="Long" resultType="int">
|
||||||
|
|
@ -106,9 +105,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
<if test="leader != null and leader != ''">leader,</if>
|
<if test="leader != null and leader != ''">leader,</if>
|
||||||
<if test="phone != null and phone != ''">phone,</if>
|
<if test="phone != null and phone != ''">phone,</if>
|
||||||
<if test="email != null and email != ''">email,</if>
|
<if test="email != null and email != ''">email,</if>
|
||||||
<if test="byteApiKey != null">byte_api_key,</if>
|
|
||||||
<if test="modelParm != null">model_parm,</if>
|
|
||||||
<if test="project != null">project,</if>
|
|
||||||
<if test="balance != null">balance,</if>
|
<if test="balance != null">balance,</if>
|
||||||
<if test="maxUserCount != null">max_user_count,</if>
|
<if test="maxUserCount != null">max_user_count,</if>
|
||||||
<if test="status != null">status,</if>
|
<if test="status != null">status,</if>
|
||||||
|
|
@ -123,9 +119,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
<if test="leader != null and leader != ''">#{leader},</if>
|
<if test="leader != null and leader != ''">#{leader},</if>
|
||||||
<if test="phone != null and phone != ''">#{phone},</if>
|
<if test="phone != null and phone != ''">#{phone},</if>
|
||||||
<if test="email != null and email != ''">#{email},</if>
|
<if test="email != null and email != ''">#{email},</if>
|
||||||
<if test="byteApiKey != null">#{byteApiKey},</if>
|
|
||||||
<if test="modelParm != null">#{modelParm},</if>
|
|
||||||
<if test="project != null">#{project},</if>
|
|
||||||
<if test="balance != null">#{balance},</if>
|
<if test="balance != null">#{balance},</if>
|
||||||
<if test="maxUserCount != null">#{maxUserCount},</if>
|
<if test="maxUserCount != null">#{maxUserCount},</if>
|
||||||
<if test="status != null">#{status},</if>
|
<if test="status != null">#{status},</if>
|
||||||
|
|
@ -144,9 +137,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
<if test="leader != null">leader = #{leader},</if>
|
<if test="leader != null">leader = #{leader},</if>
|
||||||
<if test="phone != null">phone = #{phone},</if>
|
<if test="phone != null">phone = #{phone},</if>
|
||||||
<if test="email != null">email = #{email},</if>
|
<if test="email != null">email = #{email},</if>
|
||||||
<if test="byteApiKey != null">byte_api_key = #{byteApiKey},</if>
|
|
||||||
<if test="modelParm != null">model_parm = #{modelParm},</if>
|
|
||||||
<if test="project != null">project = #{project},</if>
|
|
||||||
<if test="balance != null">balance = #{balance},</if>
|
<if test="balance != null">balance = #{balance},</if>
|
||||||
<if test="maxUserCount != null">max_user_count = #{maxUserCount},</if>
|
<if test="maxUserCount != null">max_user_count = #{maxUserCount},</if>
|
||||||
<if test="status != null and status != ''">status = #{status},</if>
|
<if test="status != null and status != ''">status = #{status},</if>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
-- =============================================================================
|
||||||
|
-- 部门火山配置迁表:ai_dept_ark_config 唯一约束、数据搬迁、sys_dept 删除三列
|
||||||
|
-- 部署顺序:在已有 ai_dept_ark_config 与 sys_dept 火山列的前提下执行;
|
||||||
|
-- 可重复执行 INSERT 段(NOT EXISTS 跳过已搬迁行)。
|
||||||
|
-- =============================================================================
|
||||||
|
|
||||||
|
-- 1) 一部门一行(若已存在同名索引请跳过本步)
|
||||||
|
ALTER TABLE `ai_dept_ark_config`
|
||||||
|
ADD UNIQUE INDEX `uk_dept_id` (`dept_id`);
|
||||||
|
|
||||||
|
-- 2) 从 sys_dept 搬迁至 ai_dept_ark_config(仅一级、二级部门,且三字段至少其一非空)
|
||||||
|
INSERT INTO `ai_dept_ark_config` (`dept_id`, `model_parm`, `project`, `byte_api_key`, `create_time`)
|
||||||
|
SELECT
|
||||||
|
d.`dept_id`,
|
||||||
|
d.`model_parm`,
|
||||||
|
d.`project`,
|
||||||
|
d.`byte_api_key`,
|
||||||
|
NOW()
|
||||||
|
FROM `sys_dept` d
|
||||||
|
WHERE d.`del_flag` = '0'
|
||||||
|
AND d.`ancestors` IS NOT NULL
|
||||||
|
AND (
|
||||||
|
(d.`parent_id` = 0 AND d.`ancestors` = '0')
|
||||||
|
OR (CHAR_LENGTH(d.`ancestors`) - CHAR_LENGTH(REPLACE(d.`ancestors`, ',', ''))) = 1
|
||||||
|
)
|
||||||
|
AND (
|
||||||
|
NULLIF(TRIM(d.`byte_api_key`), '') IS NOT NULL
|
||||||
|
OR NULLIF(TRIM(d.`project`), '') IS NOT NULL
|
||||||
|
OR NULLIF(TRIM(d.`model_parm`), '') IS NOT NULL
|
||||||
|
)
|
||||||
|
AND NOT EXISTS (
|
||||||
|
SELECT 1 FROM `ai_dept_ark_config` a WHERE a.`dept_id` = d.`dept_id`
|
||||||
|
);
|
||||||
|
|
||||||
|
-- 3) 删除 sys_dept 上已迁移的火山列(搬迁完成后再执行)
|
||||||
|
ALTER TABLE `sys_dept`
|
||||||
|
DROP COLUMN `byte_api_key`,
|
||||||
|
DROP COLUMN `project`,
|
||||||
|
DROP COLUMN `model_parm`;
|
||||||
Loading…
Reference in New Issue