ai_images/admin-ui/src/views/system/dept/index.vue

598 lines
19 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch">
<el-form-item label="部门名称" prop="deptName">
<el-input
v-model="queryParams.deptName"
placeholder="请输入部门名称"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="部门状态" clearable>
<el-option
v-for="dict in dict.type.sys_normal_disable"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="info"
plain
icon="el-icon-sort"
size="mini"
@click="toggleExpandAll"
>展开/折叠</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table
v-if="refreshTable"
v-loading="loading"
:data="deptList"
row-key="deptId"
:default-expand-all="isExpandAll"
:tree-props="{children: 'children', hasChildren: 'hasChildren'}"
>
<el-table-column prop="deptName" label="部门名称" width="260"></el-table-column>
<el-table-column prop="orderNum" label="排序" width="200"></el-table-column>
<el-table-column prop="maxUserCount" label="账号上限" width="100" align="center">
<template slot-scope="scope">
<span>{{ scope.row.maxUserCount != null && scope.row.maxUserCount > 0 ? scope.row.maxUserCount : '不限制' }}</span>
</template>
</el-table-column>
<el-table-column prop="status" label="状态" width="100">
<template slot-scope="scope">
<dict-tag :options="dict.type.sys_normal_disable" :value="scope.row.status"/>
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" width="200">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<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
size="mini"
type="text"
icon="el-icon-edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['system:dept:edit']"
>修改</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-plus"
@click="handleAdd(scope.row)"
v-if="isFirstLevelRow(scope.row)"
v-hasPermi="['system:dept:add']"
>新增</el-button>
<el-button
v-if="scope.row.parentId != 0"
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
v-hasPermi="['system:dept:remove']"
>删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 添加或修改部门对话框 -->
<el-dialog :title="title" :visible.sync="open" width="800px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-row>
<el-col :span="24" v-if="form.parentId !== 0">
<el-form-item label="上级部门" prop="parentId">
<treeselect v-model="form.parentId" :options="deptOptions" :normalizer="normalizer" placeholder="选择上级部门" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="部门名称" prop="deptName">
<el-input v-model="form.deptName" placeholder="请输入部门名称" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="显示排序" prop="orderNum">
<el-input-number v-model="form.orderNum" controls-position="right" :min="0" :disabled="isFirstLevelEditForm" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="负责人" prop="leader">
<el-input v-model="form.leader" placeholder="请输入负责人" maxlength="20" :disabled="isFirstLevelEditForm" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="联系电话" prop="phone">
<el-input v-model="form.phone" placeholder="请输入联系电话" maxlength="11" :disabled="isFirstLevelEditForm" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="邮箱" prop="email">
<el-input v-model="form.email" placeholder="请输入邮箱" maxlength="50" :disabled="isFirstLevelEditForm" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="部门状态">
<el-radio-group v-model="form.status" :disabled="isFirstLevelEditForm">
<el-radio
v-for="dict in dict.type.sys_normal_disable"
:key="dict.value"
:label="dict.value"
>{{dict.label}}</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="账号上限" prop="maxUserCount">
<el-input-number
v-model="form.maxUserCount"
:min="0"
:max="999999"
:precision="0"
controls-position="right"
placeholder="0=不限制"
style="width: 100%"
:disabled="isFirstLevelEditForm"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<p class="model-parm-hint" style="margin: 0; padding-top: 8px">&nbsp;&nbsp;限制本部门下「启用」状态账号数量0 或不填表示不限制。</p>
</el-col>
</el-row>
</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-form-item label="Byte API Key">
<el-input
v-model="arkForm.byteApiKey"
type="password"
show-password
placeholder="选填"
maxlength="255"
/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="火山配置项目">
<el-input
v-model="arkForm.project"
type="password"
show-password
placeholder="选填"
maxlength="255"
/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="视频模型">
<div class="model-parm-block">
<div
v-for="(row, idx) in arkModelParamRows"
:key="'ark-mp-' + idx"
class="model-parm-row"
>
<el-input
v-model="row.label"
placeholder="显示名称(如 Seedance 2.0"
class="model-parm-input-label"
/>
<el-input
v-model="row.value"
placeholder="Endpoint / 模型 IDep-…)"
class="model-parm-input-value"
/>
<el-button
type="text"
icon="el-icon-delete"
:disabled="arkModelParamRows.length <= 1"
@click="removeArkModelParamRow(idx)"
/>
</div>
<el-button type="text" icon="el-icon-plus" @click="addArkModelParamRow">添加模型</el-button>
<p class="model-parm-hint">
保存为 JSON 写入 ai_dept_ark_config.model_parm门户「视频生成」按 ai_user.dept_id 与本部门配置读取。
留空则使用 portal.video.models。
</p>
</div>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitArkForm" v-hasPermi="['system:dept:edit']">确 定</el-button>
<el-button @click="arkOpen = false"> </el-button>
</div>
</el-dialog>
</div>
</template>
<style scoped>
.model-parm-block {
width: 100%;
}
.model-parm-row {
display: flex;
align-items: center;
margin-bottom: 8px;
}
.model-parm-input-label {
width: 38%;
margin-right: 8px;
}
.model-parm-input-value {
flex: 1;
margin-right: 8px;
}
.model-parm-hint {
margin: 8px 0 0;
font-size: 12px;
color: #909399;
line-height: 1.5;
}
.form-tip {
margin-right: 16px;
color: #e6a23c;
font-size: 12px;
}
</style>
<script>
import { listDept, getDept, delDept, addDept, updateDept, listDeptExcludeChild, getDeptArk, updateDeptArk } from "@/api/system/dept"
import Treeselect from "@riophae/vue-treeselect"
import "@riophae/vue-treeselect/dist/vue-treeselect.css"
export default {
name: "Dept",
dicts: ['sys_normal_disable'],
components: { Treeselect },
data() {
return {
// 遮罩层
loading: true,
// 显示搜索条件
showSearch: true,
// 表格树数据
deptList: [],
// 部门树选项
deptOptions: [],
// 弹出层标题
title: "",
// 是否显示弹出层
open: false,
arkOpen: false,
arkDeptId: null,
arkForm: {
byteApiKey: undefined,
project: undefined,
modelParm: undefined
},
arkModelParamRows: [{ label: '', value: '' }],
// 是否展开,默认全部展开
isExpandAll: true,
// 重新渲染表格状态
refreshTable: true,
// 查询参数
queryParams: {
deptName: undefined,
status: undefined
},
// 表单参数
form: {},
originalForm: {},
// 表单校验
rules: {
parentId: [
{ required: true, message: "上级部门不能为空", trigger: "blur" }
],
deptName: [
{ required: true, message: "部门名称不能为空", trigger: "blur" }
],
orderNum: [
{ required: true, message: "显示排序不能为空", trigger: "blur" }
],
email: [
{
type: "email",
message: "请输入正确的邮箱地址",
trigger: ["blur", "change"]
}
],
phone: [
{
pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
message: "请输入正确的手机号码",
trigger: "blur"
}
]
}
}
},
created() {
this.getList()
},
computed: {
isFirstLevelEditForm() {
return this.form.deptId !== undefined && this.isFirstLevelRow(this.form)
}
},
methods: {
isFirstLevelRow(row) {
if (!row) {
return false
}
return Number(row.parentId) === 0 && String(row.ancestors || "") === "0"
},
isSecondLevelRow(row) {
if (!row) {
return false
}
const ancestors = String(row.ancestors || "").split(",").filter(Boolean)
return ancestors.length === 2
},
getFirstLevelDeptOptions(nodes) {
if (!Array.isArray(nodes)) {
return []
}
return nodes.filter(item => this.isFirstLevelRow(item)).map(item => {
const current = { ...item }
delete current.children
return current
})
},
syncArkModelRowsFromForm() {
this.arkModelParamRows = [{ label: '', value: '' }]
const raw = this.arkForm.modelParm
if (!raw || String(raw).trim() === '') {
return
}
try {
const arr = JSON.parse(raw)
if (Array.isArray(arr) && arr.length) {
this.arkModelParamRows = arr.map(x => ({
label: (x && x.label) ? String(x.label) : '',
value: (x && x.value) ? String(x.value) : ''
}))
}
} catch (e) {
this.arkModelParamRows = [{ label: '', value: '' }]
}
},
buildArkModelParmPayload() {
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
}
this.arkModelParamRows.splice(idx, 1)
},
resetArkForm() {
this.arkDeptId = null
this.arkForm = {
byteApiKey: undefined,
project: undefined,
modelParm: undefined
}
this.arkModelParamRows = [{ label: '', value: '' }]
if (this.$refs.arkFormRef) {
this.$refs.arkFormRef.resetFields()
}
},
handleArkConfig(row) {
if (!this.isFirstLevelRow(row) && !this.isSecondLevelRow(row)) {
return
}
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() {
this.loading = true
listDept(this.queryParams).then(response => {
this.deptList = this.handleTree(response.data, "deptId")
this.loading = false
})
},
/** 转换部门数据结构 */
normalizer(node) {
if (node.children && !node.children.length) {
delete node.children
}
return {
id: node.deptId,
label: node.deptName,
children: node.children
}
},
// 取消按钮
cancel() {
this.open = false
this.reset()
},
// 表单重置
reset() {
this.form = {
deptId: undefined,
parentId: undefined,
ancestors: undefined,
deptName: undefined,
orderNum: undefined,
leader: undefined,
phone: undefined,
email: undefined,
maxUserCount: undefined,
status: "0"
}
this.originalForm = {}
this.resetForm("form")
},
/** 搜索按钮操作 */
handleQuery() {
this.getList()
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm")
this.handleQuery()
},
/** 新增按钮操作 */
handleAdd(row) {
this.reset()
if (row !== undefined) {
if (!this.isFirstLevelRow(row)) {
this.$modal.msgError("仅允许在一级部门下新增二级部门")
return
}
this.form.parentId = row.deptId
}
this.open = true
this.title = "添加二级部门"
listDept().then(response => {
this.deptOptions = this.getFirstLevelDeptOptions(this.handleTree(response.data, "deptId"))
})
},
/** 展开/折叠操作 */
toggleExpandAll() {
this.refreshTable = false
this.isExpandAll = !this.isExpandAll
this.$nextTick(() => {
this.refreshTable = true
})
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset()
getDept(row.deptId).then(response => {
this.form = response.data
this.originalForm = { ...response.data }
this.open = true
this.title = "修改部门"
listDeptExcludeChild(row.deptId).then(response => {
const allOptions = this.handleTree(response.data, "deptId")
this.deptOptions = this.getFirstLevelDeptOptions(allOptions)
if (this.deptOptions.length == 0) {
const noResultsOptions = { deptId: this.form.parentId, deptName: this.form.parentName, children: [] }
this.deptOptions.push(noResultsOptions)
}
})
})
},
/** 提交按钮 */
submitForm: function() {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.deptId == undefined && !this.deptOptions.some(item => Number(item.deptId) === Number(this.form.parentId))) {
this.$modal.msgError("仅允许在一级部门下创建二级部门")
return
}
if (this.form.deptId != undefined) {
if (this.isFirstLevelEditForm) {
const oldDept = this.originalForm || {}
this.form.parentId = oldDept.parentId
this.form.orderNum = oldDept.orderNum
this.form.leader = oldDept.leader
this.form.phone = oldDept.phone
this.form.email = oldDept.email
this.form.status = oldDept.status
this.form.maxUserCount = oldDept.maxUserCount
}
updateDept(this.form).then(response => {
this.$modal.msgSuccess("修改成功")
this.open = false
this.getList()
})
} else {
addDept(this.form).then(response => {
this.$modal.msgSuccess("新增成功")
this.open = false
this.getList()
})
}
}
})
},
/** 删除按钮操作 */
handleDelete(row) {
this.$modal.confirm('是否确认删除名称为"' + row.deptName + '"的数据项?').then(function() {
return delDept(row.deptId)
}).then(() => {
this.getList()
this.$modal.msgSuccess("删除成功")
}).catch(() => {})
}
}
}
</script>