ai_images/admin-ui/src/views/ai/user/index.vue

751 lines
23 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"
label-width="68px"
>
<el-form-item label="用户ID" prop="userId">
<el-input
v-model="queryParams.userId"
placeholder="请输入用户ID"
clearable
style="width: 150px"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="账号" prop="username">
<el-input
v-model="queryParams.username"
placeholder="请输入账号"
clearable
style="width: 150px"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="状态" prop="status" label-width="40px">
<el-select v-model="queryParams.status" placeholder="用户状态" clearable style="width: 80px">
<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 label="归属团队" prop="deptId">
<treeselect
v-model="queryParams.deptId"
:options="deptOptions"
:normalizer="deptNormalizer"
placeholder="全部"
clearable
style="width: 220px"
/>
</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-button
type="primary"
plain
icon="el-icon-plus"
size="mini"
@click="handleAdd"
v-hasPermi="['ai:user:add']"
>新增</el-button>
<el-button
type="danger"
plain
icon="el-icon-delete"
size="mini"
:disabled="multiple"
@click="handleDelete()"
v-hasPermi="['ai:user:remove']"
>删除</el-button>
<el-button
type="warning"
plain
icon="el-icon-download"
size="mini"
@click="handleExport"
v-hasPermi="['ai:user:export']"
>导出</el-button>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-form-item>
</el-form>
<el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="50" align="center" />
<el-table-column label="主键ID" align="center" prop="id" width="60" />
<el-table-column label="用户ID" align="center" prop="userId" />
<el-table-column label="账号" align="center" prop="username" />
<!--
<el-table-column label="上级ID" align="center" prop="superiorUuid" />
<el-table-column label="上级账号" align="center" prop="superiorName" />
-->
<el-table-column label="用户昵称" align="center" prop="nickname" />
<el-table-column label="归属团队" align="center" prop="deptName" width="120" show-overflow-tooltip />
<!--
<el-table-column label="邮箱" align="center" prop="email" />
<el-table-column label="性别" align="center" prop="gender">
<template slot-scope="scope">
<el-tag v-if="scope.row.gender === 1">男</el-tag>
<el-tag v-else type="danger">女</el-tag>
</template>
</el-table-column>
-->
<el-table-column label="状态" align="center" key="status" width="60">
<template slot-scope="scope">
<el-switch
v-model="scope.row.status"
:active-value="0"
:inactive-value="1"
@change="handleStatusChange(scope.row)"
></el-switch>
</template>
</el-table-column>
<!--
<el-table-column label="邀请码" align="center" prop="invitationCode" />
-->
<el-table-column label="登录时间" align="center" prop="loginTime" width="150">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.loginTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
</template>
</el-table-column>
<el-table-column label="剩余积分" align="center" prop="balance" width="120">
<template slot-scope="scope">
<span>{{ formatThousands(scope.row.balance) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="460">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-office-building"
@click="handleOpenAssignDept(scope.row)"
v-hasPermi="['ai:user:edit']"
>分配团队</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="updatePassword(scope.row)"
v-hasPermi="['ai:user:edit']"
>修改密码</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-download"
@click="openDeptScoreDialog(scope.row, 'issue')"
v-hasPermi="['ai:user:deptScoreIssue']"
>下放积分</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-upload2"
@click="openDeptScoreDialog(scope.row, 'reclaim')"
v-hasPermi="['ai:user:deptScoreReclaim']"
>回收积分</el-button>
<!-- 修改余额功能已关闭
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="updateBalance(scope.row)"
v-hasPermi="['ai:user:remove']"
>修改余额</el-button>
-->
<el-button
size="mini"
type="text"
icon="el-icon-edit-outline"
@click="handleUpdate(scope.row)"
v-hasPermi="['ai:user:edit']"
>修改</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
v-hasPermi="['ai:user:remove']"
>删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total>0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
<!-- 添加或修改ai-用户信息对话框 -->
<el-dialog :title="title" :visible.sync="open" width="520px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="88px">
<el-form-item label="用户账号" prop="username">
<el-input
v-model="form.username"
placeholder="门户登录账号,必填"
:disabled="form.id != null"
/>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input
v-model="form.password"
type="password"
show-password
:placeholder="form.id != null ? '不填表示不修改密码' : '请输入登录密码'"
autocomplete="new-password"
/>
</el-form-item>
<el-form-item label="用户昵称" prop="nickname">
<el-input v-model="form.nickname" placeholder="请输入用户昵称" />
</el-form-item>
<el-form-item label="性别" prop="gender">
<el-input v-model="form.gender" placeholder="请输入性别1-男2-女" />
</el-form-item>
<el-form-item label="手机号码" prop="phone">
<el-input v-model="form.phone" placeholder="请输入手机号码" />
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-input v-model="form.email" placeholder="请输入邮箱" />
</el-form-item>
<el-form-item label="生日" prop="birthday">
<el-date-picker
clearable
v-model="form.birthday"
type="date"
value-format="yyyy-MM-dd"
placeholder="请选择生日"
></el-date-picker>
</el-form-item>
<el-form-item v-if="form.id != null" label="剩余积分" prop="balance">
<el-input v-model="form.balance" disabled placeholder="-" />
<div style="color: #909399; font-size: 12px; line-height: 1.5; margin-top: 4px">
剩余积分仅可通过「下放积分」「回收积分」调整
</div>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm">确 定</el-button>
<el-button @click="cancel">取 消</el-button>
</div>
</el-dialog>
<!-- 修改密码对话框 -->
<el-dialog :title="title" :visible.sync="openUpdatePassword" width="500px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-form-item label="密码" prop="password">
<el-input v-model="form.password" placeholder="请输入密码" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitUpdatePassword">确 定</el-button>
<el-button @click="cancelPassword">取 消</el-button>
</div>
</el-dialog>
<!-- 分配团队 -->
<el-dialog title="分配归属团队" :visible.sync="assignDeptOpen" width="480px" append-to-body @close="cancelAssignDept">
<el-form label-width="88px">
<el-form-item label="归属团队">
<treeselect
v-model="assignForm.deptId"
:options="deptOptions"
:normalizer="deptNormalizer"
placeholder="不选则不归属任何团队"
clearable
/>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitAssignDept">确 定</el-button>
<el-button @click="cancelAssignDept">取 消</el-button>
</div>
</el-dialog>
<!-- 部门积分下放 / 回收 -->
<el-dialog
:title="deptScoreMode === 'issue' ? '下放积分' : '回收积分'"
:visible.sync="deptScoreOpen"
width="480px"
append-to-body
@close="cancelDeptScore"
>
<el-form ref="deptScoreFormRef" :model="deptScoreForm" :rules="deptScoreRules" label-width="88px">
<el-form-item label="所属团队">
<span>{{ deptScoreForm.deptName || "—" }}</span>
</el-form-item>
<el-form-item label="用户账号">
<span>{{ deptScoreForm.username }}</span>
</el-form-item>
<el-form-item label="积分数量" prop="amount">
<el-input-number
v-model="deptScoreForm.amount"
:min="1"
:max="100000000"
:precision="0"
:step="1"
controls-position="right"
style="width: 100%"
/>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input
v-model="deptScoreForm.remark"
type="textarea"
:rows="2"
maxlength="50"
show-word-limit
placeholder="选填最多50字"
/>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitDeptScore">确 定</el-button>
<el-button @click="cancelDeptScore">取 消</el-button>
</div>
</el-dialog>
<!-- 修改余额功能已关闭
<el-dialog :title="title" :visible.sync="openUpdateBalance" width="500px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-form-item label="余额" prop="balance">
<el-input v-model="form.balance" placeholder="请输入余额" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="handleChangeBalance">确 定</el-button>
<el-button @click="cancelBalance"> </el-button>
</div>
</el-dialog>
-->
</div>
</template>
<script>
import {
listUser,
getUser,
delUser,
addUser,
updateUser,
changeUserStatus,
updatePassword,
assignAiUserDept,
issueDeptScore,
reclaimDeptScore
} from "@/api/ai/user";
import { listDept } from "@/api/ai/dept";
import Treeselect from "@riophae/vue-treeselect";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
export default {
name: "User",
dicts: ["sys_normal_disable", "sys_user_sex"],
components: { Treeselect },
data() {
return {
// 遮罩层
loading: true,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// ai-用户信息表格数据
userList: [],
// 弹出层标题
title: "",
// 是否显示弹出层
open: false,
openUpdatePassword: false,
deptScoreOpen: false,
deptScoreMode: "issue",
deptScoreForm: {
userId: null,
username: "",
deptName: "",
amount: undefined,
remark: ""
},
deptScoreRules: {
amount: [
{ required: true, message: "请输入积分数量", trigger: "blur" },
{
type: "number",
min: 1,
max: 100000000,
message: "请输入 1100000000 的整数",
trigger: "blur"
}
],
remark: [{ max: 50, message: "备注最多50个字", trigger: "blur" }]
},
assignDeptOpen: false,
deptOptions: [],
assignForm: {
id: null,
deptId: null
},
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
nickname: null,
gender: null,
avatar: null,
phone: null,
password: null,
openid: null,
status: "0",
email: null,
birthday: null,
invitationCode: null,
paymentUrl: null,
loginTime: null,
balance: null,
superiorName: null,
deptId: null
},
// 表单参数
form: {},
// 表单校验
rules: {
username: [{ required: true, message: "用户账号不能为空", trigger: "blur" }],
password: [
{
validator: (rule, value, callback) => {
if (this.form.id == null && (!value || !String(value).trim())) {
callback(new Error("密码不能为空"));
} else {
callback();
}
},
trigger: "blur"
}
]
}
};
},
created() {
this.loadDeptTree();
this.getList();
},
methods: {
/** 千位分节en-US整数空为 — */
formatThousands(value) {
if (value === null || value === undefined || value === "") {
return "—";
}
const n = Number(value);
if (Number.isNaN(n)) {
return String(value);
}
return n.toLocaleString("en-US", { maximumFractionDigits: 0 });
},
loadDeptTree() {
listDept().then(res => {
this.deptOptions = this.handleTree(res.data, "deptId");
});
},
deptNormalizer(node) {
if (node.children && !node.children.length) {
delete node.children;
}
return {
id: node.deptId,
label: node.deptName,
children: node.children
};
},
handleOpenAssignDept(row) {
getUser(row.id).then(res => {
this.assignForm = {
id: res.data.id,
deptId: res.data.deptId
};
this.assignDeptOpen = true;
});
},
submitAssignDept() {
const payload = {
id: this.assignForm.id,
deptId: this.assignForm.deptId != null ? this.assignForm.deptId : null
};
assignAiUserDept(payload).then(() => {
this.$modal.msgSuccess("已保存");
this.assignDeptOpen = false;
this.getList();
});
},
cancelAssignDept() {
this.assignDeptOpen = false;
this.assignForm = { id: null, deptId: null };
},
// 更多操作触发
handleCommand(command, row) {
switch (command) {
case "updatePassword":
this.updatePassword(row);
break;
// case "updateBalance":
// this.updateBalance(row);
// break;
default:
break;
}
},
updatePassword(row) {
this.reset();
this.form.id = row.id;
this.title = "修改密码";
this.openUpdatePassword = true;
},
submitUpdatePassword() {
updatePassword(this.form.id, this.form.password).then(() => {
this.$modal.msgSuccess("修改成功");
this.openUpdatePassword = false;
});
return;
},
openDeptScoreDialog(row, mode) {
if (!row.deptId) {
this.$modal.msgWarning("请先分配归属团队后再操作积分");
return;
}
this.deptScoreMode = mode;
this.deptScoreForm = {
userId: row.id,
username: row.username || row.userId || "",
deptName: row.deptName || "",
amount: undefined,
remark: ""
};
this.deptScoreOpen = true;
this.$nextTick(() => {
if (this.$refs.deptScoreFormRef) {
this.$refs.deptScoreFormRef.clearValidate();
}
});
},
submitDeptScore() {
this.$refs.deptScoreFormRef.validate(valid => {
if (!valid) {
return;
}
const raw = this.deptScoreForm.amount;
const amount = typeof raw === "number" ? Math.trunc(raw) : parseInt(String(raw), 10);
if (!Number.isFinite(amount) || amount < 1 || amount > 100000000) {
this.$modal.msgWarning("请输入 1100000000 的整数积分");
return;
}
const payload = {
userId: this.deptScoreForm.userId,
amount,
remark: this.deptScoreForm.remark || undefined
};
const req = this.deptScoreMode === "issue" ? issueDeptScore : reclaimDeptScore;
req(payload).then(() => {
this.$modal.msgSuccess("操作成功");
this.deptScoreOpen = false;
this.getList();
});
});
},
cancelDeptScore() {
this.deptScoreOpen = false;
this.deptScoreForm = { userId: null, username: "", deptName: "", amount: undefined, remark: "" };
},
// updateBalance(row) {
// this.reset();
// const id = row.id || this.ids;
// getUser(id).then(response => {
// this.form = response.data;
// this.openUpdateBalance = true;
// this.title = "修改余额";
// });
// },
/** 查询ai-用户信息列表 */
getList() {
this.loading = true;
listUser(this.queryParams).then(response => {
this.userList = response.rows;
this.total = response.total;
this.loading = false;
});
},
// 用户状态修改
handleStatusChange(row) {
let text = row.status === 0 ? "启用" : "停用";
this.$modal
.confirm('确认要"' + text + '""' + row.userId + '"用户吗?')
.then(function() {
return changeUserStatus(row.id, row.status);
})
.then(() => {
this.$modal.msgSuccess(text + "成功");
})
.catch(function() {
row.status = row.status === 0 ? 1 : 0;
});
},
// 取消按钮
cancel() {
this.open = false;
this.reset();
},
// cancelBalance() {
// this.openUpdateBalance = false;
// this.reset();
// },
cancelPassword() {
this.openUpdatePassword = false;
this.reset();
},
// 表单重置
reset() {
this.form = {
id: null,
delFlag: null,
createBy: null,
createTime: null,
updateBy: null,
updateTime: null,
remark: null,
username: null,
nickname: null,
gender: null,
avatar: null,
phone: null,
password: null,
openid: null,
status: null,
email: null,
birthday: null,
invitationCode: null,
paymentUrl: null,
loginTime: null,
balance: null,
superiorId: null
};
this.resetForm("form");
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
// 多选框选中数据
handleSelectionChange(selection) {
this.ids = selection.map(item => item.id);
this.single = selection.length !== 1;
this.multiple = !selection.length;
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = "添加ai-用户信息";
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
const id = row.id || this.ids;
getUser(id).then(response => {
this.form = response.data;
this.open = true;
this.title = "修改ai-用户信息";
});
},
/** 提交按钮 */
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.id != null) {
const payload = { ...this.form };
if (!payload.password || !String(payload.password).trim()) {
delete payload.password;
}
updateUser(payload).then(() => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
});
} else {
const payload = { ...this.form };
delete payload.balance;
addUser(payload).then(() => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
});
}
}
});
},
// handleChangeBalance() {
// this.$refs["form"].validate(valid => {
// if (!valid) return;
// changeBalance(this.form.id, this.form.balance).then(() => {
// this.$modal.msgSuccess("修改成功");
// this.openUpdateBalance = false;
// this.getList();
// });
// });
// },
/** 删除按钮操作 */
handleDelete(row) {
const ids = row && row.id != null ? row.id : this.ids;
if (ids == null || (Array.isArray(ids) && !ids.length)) {
this.$modal.msgWarning("请选择要删除的数据");
return;
}
const idParam = Array.isArray(ids) ? ids.join(",") : ids;
this.$modal
.confirm('是否确认删除ai-用户信息编号为"' + idParam + '"的数据项?')
.then(() => {
return delUser(idParam);
})
.then(() => {
this.getList();
this.$modal.msgSuccess("删除成功");
})
.catch(() => {});
},
/** 导出按钮操作 */
handleExport() {
this.download(
"ai/user/export",
{
...this.queryParams
},
`user_${new Date().getTime()}.xlsx`
);
}
}
};
</script>