feat: AI用户 - 下放/回收积分,去掉设置余额功能。恢复AiDeptController
This commit is contained in:
parent
c92f531f1b
commit
db2052b9fd
|
|
@ -56,18 +56,18 @@ export function changeUserStatus(id, status) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function changeBalance(id, balance) {
|
// 修改余额接口已关闭(与后端 AiUserController.changeBalance 一致停用)
|
||||||
const data = {
|
// export function changeBalance(id, balance) {
|
||||||
id,
|
// const data = {
|
||||||
balance
|
// id,
|
||||||
}
|
// balance
|
||||||
return request({
|
// }
|
||||||
url: '/ai/user/changeBalance',
|
// return request({
|
||||||
method: 'put',
|
// url: '/ai/user/changeBalance',
|
||||||
data: data
|
// method: 'put',
|
||||||
})
|
// data: data
|
||||||
}
|
// })
|
||||||
|
// }
|
||||||
|
|
||||||
// 用户状态修改
|
// 用户状态修改
|
||||||
export function updatePassword(id, newPassword) {
|
export function updatePassword(id, newPassword) {
|
||||||
|
|
@ -90,3 +90,21 @@ export function assignAiUserDept(data) {
|
||||||
data
|
data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 部门积分下放至用户 */
|
||||||
|
export function issueDeptScore(data) {
|
||||||
|
return request({
|
||||||
|
url: '/ai/user/dept-score/issue',
|
||||||
|
method: 'put',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 用户积分回收至部门 */
|
||||||
|
export function reclaimDeptScore(data) {
|
||||||
|
return request({
|
||||||
|
url: '/ai/user/dept-score/reclaim',
|
||||||
|
method: 'put',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -106,8 +106,10 @@
|
||||||
<el-table-column label="主键ID" align="center" prop="id" width="90" />
|
<el-table-column label="主键ID" align="center" prop="id" width="90" />
|
||||||
<el-table-column label="用户ID" align="center" prop="userId" />
|
<el-table-column label="用户ID" align="center" prop="userId" />
|
||||||
<el-table-column label="用户账号" align="center" prop="username" />
|
<el-table-column label="用户账号" align="center" prop="username" />
|
||||||
|
<!--
|
||||||
<el-table-column label="上级ID" align="center" prop="superiorUuid" />
|
<el-table-column label="上级ID" align="center" prop="superiorUuid" />
|
||||||
<el-table-column label="上级账号" align="center" prop="superiorName" />
|
<el-table-column label="上级账号" align="center" prop="superiorName" />
|
||||||
|
-->
|
||||||
<el-table-column label="用户昵称" align="center" prop="nickname" />
|
<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="deptName" width="120" show-overflow-tooltip />
|
||||||
<el-table-column label="邮箱" align="center" prop="email" />
|
<el-table-column label="邮箱" align="center" prop="email" />
|
||||||
|
|
@ -135,7 +137,7 @@
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="余额" align="center" prop="balance" />
|
<el-table-column label="余额" align="center" prop="balance" />
|
||||||
<el-table-column label="source" align="center" prop="source" />
|
<el-table-column label="source" align="center" prop="source" />
|
||||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="310">
|
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="460">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-button
|
<el-button
|
||||||
size="mini"
|
size="mini"
|
||||||
|
|
@ -151,6 +153,21 @@
|
||||||
@click="updatePassword(scope.row)"
|
@click="updatePassword(scope.row)"
|
||||||
v-hasPermi="['ai:user:edit']"
|
v-hasPermi="['ai:user:edit']"
|
||||||
>修改密码</el-button>
|
>修改密码</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
|
<el-button
|
||||||
size="mini"
|
size="mini"
|
||||||
type="text"
|
type="text"
|
||||||
|
|
@ -158,6 +175,7 @@
|
||||||
@click="updateBalance(scope.row)"
|
@click="updateBalance(scope.row)"
|
||||||
v-hasPermi="['ai:user:remove']"
|
v-hasPermi="['ai:user:remove']"
|
||||||
>修改余额</el-button>
|
>修改余额</el-button>
|
||||||
|
-->
|
||||||
<el-button
|
<el-button
|
||||||
size="mini"
|
size="mini"
|
||||||
type="text"
|
type="text"
|
||||||
|
|
@ -263,7 +281,47 @@
|
||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</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.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-dialog :title="title" :visible.sync="openUpdateBalance" width="500px" append-to-body>
|
||||||
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
|
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
|
||||||
<el-form-item label="余额" prop="balance">
|
<el-form-item label="余额" prop="balance">
|
||||||
|
|
@ -276,6 +334,7 @@
|
||||||
<el-button @click="cancelBalance">取 消</el-button>
|
<el-button @click="cancelBalance">取 消</el-button>
|
||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
-->
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
@ -286,10 +345,11 @@ import {
|
||||||
delUser,
|
delUser,
|
||||||
addUser,
|
addUser,
|
||||||
updateUser,
|
updateUser,
|
||||||
changeBalance,
|
|
||||||
changeUserStatus,
|
changeUserStatus,
|
||||||
updatePassword,
|
updatePassword,
|
||||||
assignAiUserDept
|
assignAiUserDept,
|
||||||
|
issueDeptScore,
|
||||||
|
reclaimDeptScore
|
||||||
} from "@/api/ai/user";
|
} from "@/api/ai/user";
|
||||||
import { listDept } from "@/api/ai/dept";
|
import { listDept } from "@/api/ai/dept";
|
||||||
import Treeselect from "@riophae/vue-treeselect";
|
import Treeselect from "@riophae/vue-treeselect";
|
||||||
|
|
@ -320,7 +380,27 @@ export default {
|
||||||
// 是否显示弹出层
|
// 是否显示弹出层
|
||||||
open: false,
|
open: false,
|
||||||
openUpdatePassword: false,
|
openUpdatePassword: false,
|
||||||
openUpdateBalance: false,
|
deptScoreOpen: false,
|
||||||
|
deptScoreMode: "issue",
|
||||||
|
deptScoreForm: {
|
||||||
|
userId: null,
|
||||||
|
username: "",
|
||||||
|
amount: undefined,
|
||||||
|
remark: ""
|
||||||
|
},
|
||||||
|
deptScoreRules: {
|
||||||
|
amount: [
|
||||||
|
{ required: true, message: "请输入积分数量", trigger: "blur" },
|
||||||
|
{
|
||||||
|
type: "number",
|
||||||
|
min: 1,
|
||||||
|
max: 100000000,
|
||||||
|
message: "请输入 1~100000000 的整数",
|
||||||
|
trigger: "blur"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
remark: [{ max: 50, message: "备注最多50个字", trigger: "blur" }]
|
||||||
|
},
|
||||||
assignDeptOpen: false,
|
assignDeptOpen: false,
|
||||||
deptOptions: [],
|
deptOptions: [],
|
||||||
assignForm: {
|
assignForm: {
|
||||||
|
|
@ -337,7 +417,7 @@ export default {
|
||||||
phone: null,
|
phone: null,
|
||||||
password: null,
|
password: null,
|
||||||
openid: null,
|
openid: null,
|
||||||
status: null,
|
status: "0",
|
||||||
email: null,
|
email: null,
|
||||||
birthday: null,
|
birthday: null,
|
||||||
invitationCode: null,
|
invitationCode: null,
|
||||||
|
|
@ -417,9 +497,9 @@ export default {
|
||||||
case "updatePassword":
|
case "updatePassword":
|
||||||
this.updatePassword(row);
|
this.updatePassword(row);
|
||||||
break;
|
break;
|
||||||
case "updateBalance":
|
// case "updateBalance":
|
||||||
this.updateBalance(row);
|
// this.updateBalance(row);
|
||||||
break;
|
// break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -437,15 +517,62 @@ export default {
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
updateBalance(row) {
|
openDeptScoreDialog(row, mode) {
|
||||||
this.reset();
|
if (!row.deptId) {
|
||||||
const id = row.id || this.ids;
|
this.$modal.msgWarning("请先分配归属部门后再操作积分");
|
||||||
getUser(id).then(response => {
|
return;
|
||||||
this.form = response.data;
|
}
|
||||||
this.openUpdateBalance = true;
|
this.deptScoreMode = mode;
|
||||||
this.title = "修改余额";
|
this.deptScoreForm = {
|
||||||
|
userId: row.id,
|
||||||
|
username: row.username || row.userId || "",
|
||||||
|
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("请输入 1~100000000 的整数积分");
|
||||||
|
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: "", 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-用户信息列表 */
|
/** 查询ai-用户信息列表 */
|
||||||
getList() {
|
getList() {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
|
|
@ -475,10 +602,10 @@ export default {
|
||||||
this.open = false;
|
this.open = false;
|
||||||
this.reset();
|
this.reset();
|
||||||
},
|
},
|
||||||
cancelBalance() {
|
// cancelBalance() {
|
||||||
this.openUpdateBalance = false;
|
// this.openUpdateBalance = false;
|
||||||
this.reset();
|
// this.reset();
|
||||||
},
|
// },
|
||||||
cancelPassword() {
|
cancelPassword() {
|
||||||
this.openUpdatePassword = false;
|
this.openUpdatePassword = false;
|
||||||
this.reset();
|
this.reset();
|
||||||
|
|
@ -567,16 +694,16 @@ export default {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
handleChangeBalance() {
|
// handleChangeBalance() {
|
||||||
changeBalance;
|
// this.$refs["form"].validate(valid => {
|
||||||
this.$refs["form"].validate(valid => {
|
// if (!valid) return;
|
||||||
changeBalance(this.form.id, this.form.balance).then(response => {
|
// changeBalance(this.form.id, this.form.balance).then(() => {
|
||||||
this.$modal.msgSuccess("修改成功");
|
// this.$modal.msgSuccess("修改成功");
|
||||||
this.openUpdateBalance = false;
|
// this.openUpdateBalance = false;
|
||||||
this.getList();
|
// this.getList();
|
||||||
});
|
// });
|
||||||
});
|
// });
|
||||||
},
|
// },
|
||||||
/** 删除按钮操作 */
|
/** 删除按钮操作 */
|
||||||
handleDelete(row) {
|
handleDelete(row) {
|
||||||
const ids = row && row.id != null ? row.id : this.ids;
|
const ids = row && row.id != null ? row.id : this.ids;
|
||||||
|
|
|
||||||
|
|
@ -26,8 +26,8 @@ import com.ruoyi.system.service.ISysDeptService;
|
||||||
/**
|
/**
|
||||||
* AI 业务侧部门管理(数据源与系统部门 sys_dept 一致,权限独立)
|
* AI 业务侧部门管理(数据源与系统部门 sys_dept 一致,权限独立)
|
||||||
*/
|
*/
|
||||||
//@RestController
|
@RestController
|
||||||
//@RequestMapping("/ai/dept")
|
@RequestMapping("/ai/dept")
|
||||||
public class AiDeptController extends BaseController
|
public class AiDeptController extends BaseController
|
||||||
{
|
{
|
||||||
@Autowired
|
@Autowired
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,8 @@
|
||||||
package com.ruoyi.web.controller.ai;
|
package com.ruoyi.web.controller.ai;
|
||||||
|
|
||||||
import cn.hutool.core.util.NumberUtil;
|
|
||||||
import com.ruoyi.ai.service.IAiUserService;
|
import com.ruoyi.ai.service.IAiUserService;
|
||||||
|
import com.ruoyi.ai.service.IDeptUserScoreTransferService;
|
||||||
import com.ruoyi.common.annotation.Log;
|
import com.ruoyi.common.annotation.Log;
|
||||||
import com.ruoyi.common.constant.BalanceChangerConstants;
|
|
||||||
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.AiUser;
|
import com.ruoyi.common.core.domain.entity.AiUser;
|
||||||
|
|
@ -17,11 +16,10 @@ import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import java.math.BigDecimal;
|
import javax.validation.Valid;
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.Date;
|
import com.ruoyi.common.core.request.ai.AiUserDeptScoreRequest;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ai-用户信息Controller
|
* ai-用户信息Controller
|
||||||
|
|
@ -36,6 +34,9 @@ public class AiUserController extends BaseController {
|
||||||
@Autowired
|
@Autowired
|
||||||
private IAiUserService aiUserService;
|
private IAiUserService aiUserService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IDeptUserScoreTransferService deptUserScoreTransferService;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询ai-用户信息列表
|
* 查询ai-用户信息列表
|
||||||
|
|
@ -120,9 +121,10 @@ public class AiUserController extends BaseController {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 状态修改
|
* 管理端修改余额已关闭(如需恢复,同步放开 admin-ui 与 api/ai/user.js)
|
||||||
*/
|
*/
|
||||||
@ApiOperation("修改ai-用户状态")
|
/*
|
||||||
|
@ApiOperation("修改ai-用户余额")
|
||||||
@PreAuthorize("@ss.hasPermi('ai:user:edit')")
|
@PreAuthorize("@ss.hasPermi('ai:user:edit')")
|
||||||
@Log(title = "ai-用户信息", businessType = BusinessType.UPDATE)
|
@Log(title = "ai-用户信息", businessType = BusinessType.UPDATE)
|
||||||
@PutMapping("/changeBalance")
|
@PutMapping("/changeBalance")
|
||||||
|
|
@ -130,14 +132,15 @@ public class AiUserController extends BaseController {
|
||||||
aiUser.setUpdateBy(getUsername());
|
aiUser.setUpdateBy(getUsername());
|
||||||
// 获取原余额
|
// 获取原余额
|
||||||
AiUser u = aiUserService.selectAiUserById(aiUser.getId());
|
AiUser u = aiUserService.selectAiUserById(aiUser.getId());
|
||||||
String uuid = UUID.randomUUID().toString().replaceAll("-", "").substring(0, 8);
|
String uuid = java.util.UUID.randomUUID().toString().replaceAll("-", "").substring(0, 8);
|
||||||
String dateTime = new SimpleDateFormat("yyyyMMdd").format(new Date());
|
String dateTime = new java.text.SimpleDateFormat("yyyyMMdd").format(new java.util.Date());
|
||||||
String orderNo = dateTime + uuid;
|
String orderNo = dateTime + uuid;
|
||||||
// 计算变更余额
|
// 计算变更余额
|
||||||
BigDecimal amount = NumberUtil.sub(aiUser.getBalance(), u.getBalance());
|
java.math.BigDecimal amount = cn.hutool.core.util.NumberUtil.sub(aiUser.getBalance(), u.getBalance());
|
||||||
aiUserService.addUserBalance(orderNo, aiUser.getId(), amount, BalanceChangerConstants.SYSTEM_OPERATION);
|
aiUserService.addUserBalance(orderNo, aiUser.getId(), amount, com.ruoyi.common.constant.BalanceChangerConstants.SYSTEM_OPERATION);
|
||||||
return toAjax(1);
|
return toAjax(1);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 状态密码
|
* 状态密码
|
||||||
|
|
@ -149,6 +152,30 @@ public class AiUserController extends BaseController {
|
||||||
return toAjax(aiUserService.updatePassword(aiUser));
|
return toAjax(aiUserService.updatePassword(aiUser));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部门积分下放至当前用户余额
|
||||||
|
*/
|
||||||
|
@ApiOperation("部门积分下放至用户")
|
||||||
|
@PreAuthorize("@ss.hasPermi('ai:user:deptScoreIssue')")
|
||||||
|
@Log(title = "AI用户部门积分下放", businessType = BusinessType.UPDATE)
|
||||||
|
@PutMapping("/dept-score/issue")
|
||||||
|
public AjaxResult issueDeptScore(@Valid @RequestBody AiUserDeptScoreRequest request) {
|
||||||
|
deptUserScoreTransferService.issueDeptScore(request);
|
||||||
|
return success();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户余额回收至部门积分池
|
||||||
|
*/
|
||||||
|
@ApiOperation("用户积分回收至部门")
|
||||||
|
@PreAuthorize("@ss.hasPermi('ai:user:deptScoreReclaim')")
|
||||||
|
@Log(title = "AI用户部门积分回收", businessType = BusinessType.UPDATE)
|
||||||
|
@PutMapping("/dept-score/reclaim")
|
||||||
|
public AjaxResult reclaimDeptScore(@Valid @RequestBody AiUserDeptScoreRequest request) {
|
||||||
|
deptUserScoreTransferService.reclaimDeptScore(request);
|
||||||
|
return success();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除ai-用户信息
|
* 删除ai-用户信息
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -73,4 +73,14 @@ public class BalanceChangerConstants {
|
||||||
*/
|
*/
|
||||||
public static final int SYSTEM_OPERATION = 11;
|
public static final int SYSTEM_OPERATION = 11;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部门积分下放至用户(sys_dept.balance → ai_user.balance)
|
||||||
|
*/
|
||||||
|
public static final int DEPT_SCORE_ISSUE = 12;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户积分回收至部门(ai_user.balance → sys_dept.balance)
|
||||||
|
*/
|
||||||
|
public static final int DEPT_SCORE_RECLAIM = 13;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
package com.ruoyi.common.core.request.ai;
|
||||||
|
|
||||||
|
import javax.validation.constraints.Max;
|
||||||
|
import javax.validation.constraints.Min;
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
import javax.validation.constraints.Size;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 管理端:部门积分与 AI 用户余额互转(下放 / 回收)。
|
||||||
|
* <p>积分为整数;落库仍用 decimal 字段,由服务层转为 {@link java.math.BigDecimal}。
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class AiUserDeptScoreRequest {
|
||||||
|
|
||||||
|
/** 对应 ai_user.id(主键) */
|
||||||
|
@NotNull(message = "用户不能为空")
|
||||||
|
private Long userId;
|
||||||
|
|
||||||
|
/** 积分数量(正整数) */
|
||||||
|
@NotNull(message = "积分不能为空")
|
||||||
|
@Min(value = 1, message = "积分必须为正整数")
|
||||||
|
@Max(value = 100_000_000, message = "积分超出上限")
|
||||||
|
private Long amount;
|
||||||
|
|
||||||
|
@Size(max = 50, message = "备注最多50个字")
|
||||||
|
private String remark;
|
||||||
|
}
|
||||||
|
|
@ -11,7 +11,7 @@ public enum GroupBalanceChangeType {
|
||||||
RECHARGE(0, "充值"),
|
RECHARGE(0, "充值"),
|
||||||
REFUND(1, "退款"),
|
REFUND(1, "退款"),
|
||||||
ISSUE(2, "下发"),
|
ISSUE(2, "下发"),
|
||||||
CONSUME(3, "消费"),
|
RECLAIM(3, "回收"),
|
||||||
MANUAL_ADJUST(4, "手动修改");
|
MANUAL_ADJUST(4, "手动修改");
|
||||||
|
|
||||||
private final int code;
|
private final int code;
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,13 @@
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 与 ruoyi-framework 对齐,供部门-用户积分下放/回收 Redisson 锁使用 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.redisson</groupId>
|
||||||
|
<artifactId>redisson-spring-boot-starter</artifactId>
|
||||||
|
<version>3.17.7</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
<!-- <dependency>-->
|
<!-- <dependency>-->
|
||||||
<!-- <groupId>com.byteplus</groupId>-->
|
<!-- <groupId>com.byteplus</groupId>-->
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ public class AiBalanceChangeRecord extends BaseEntity {
|
||||||
private String uuid;
|
private String uuid;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 操作类型:0-充值 1-返佣 2-充值赠送 3-体验金赠送 4-体验金回收 5-图生图 6-一键换脸 7-快捷生图 8-快捷生视频 9-退款 10-系统操作
|
* 操作类型:0-充值 1-返佣 2-充值赠送 3-体验金赠送 4-体验金回收 5-图生图 6-一键换脸 7-快捷生图 8-快捷生视频 9-退款 10-系统操作 12-部门下放积分 13-回收至部门
|
||||||
*/
|
*/
|
||||||
@Excel(name = "操作类型")
|
@Excel(name = "操作类型")
|
||||||
private Integer type;
|
private Integer type;
|
||||||
|
|
|
||||||
|
|
@ -30,4 +30,9 @@ public interface AiOrderMapper extends BaseMapper<AiOrder> {
|
||||||
|
|
||||||
@Select("SELECT * FROM ai_order WHERE third_party_order_num = #{id} LIMIT 1")
|
@Select("SELECT * FROM ai_order WHERE third_party_order_num = #{id} LIMIT 1")
|
||||||
AiOrder selectOneByThirdPartyOrderNum(@Param("id") String id);
|
AiOrder selectOneByThirdPartyOrderNum(@Param("id") String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 未完结订单数量:del_flag=0 且 status 非已完成(1)、非失败(2),即进行中(0)等
|
||||||
|
*/
|
||||||
|
int countOpenOrdersByUserId(@Param("userId") Long userId);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
package com.ruoyi.ai.service;
|
||||||
|
|
||||||
|
import com.ruoyi.common.core.request.ai.AiUserDeptScoreRequest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部门积分与 AI 用户余额互转(下放 / 回收),含 Redisson 锁。
|
||||||
|
*/
|
||||||
|
public interface IDeptUserScoreTransferService {
|
||||||
|
|
||||||
|
void issueDeptScore(AiUserDeptScoreRequest request);
|
||||||
|
|
||||||
|
void reclaimDeptScore(AiUserDeptScoreRequest request);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,135 @@
|
||||||
|
package com.ruoyi.ai.service.impl;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.redisson.api.RLock;
|
||||||
|
import org.redisson.api.RedissonClient;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import com.ruoyi.ai.service.IAiUserService;
|
||||||
|
import com.ruoyi.ai.service.IDeptUserScoreTransferService;
|
||||||
|
import com.ruoyi.common.core.domain.entity.AiUser;
|
||||||
|
import com.ruoyi.common.core.domain.entity.SysDept;
|
||||||
|
import com.ruoyi.common.core.request.ai.AiUserDeptScoreRequest;
|
||||||
|
import com.ruoyi.common.exception.ServiceException;
|
||||||
|
import com.ruoyi.common.utils.SecurityUtils;
|
||||||
|
import com.ruoyi.common.utils.StringUtils;
|
||||||
|
import com.ruoyi.system.service.ISysDeptService;
|
||||||
|
/**
|
||||||
|
* 部门与用户积分互转:先占 Redisson 锁,再进入事务内层。
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class DeptUserScoreTransferServiceImpl implements IDeptUserScoreTransferService {
|
||||||
|
|
||||||
|
private static final String USER_LOCK_PREFIX = "ai:user-score:";
|
||||||
|
private static final int LOCK_WAIT_SECONDS = 10;
|
||||||
|
private static final int LOCK_LEASE_SECONDS = 10;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RedissonClient redissonClient;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IAiUserService aiUserService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private DeptUserScoreTransferTxService deptUserScoreTransferTxService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISysDeptService deptService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void issueDeptScore(AiUserDeptScoreRequest request) {
|
||||||
|
AiUser user = loadUserForDeptOp(request.getUserId());
|
||||||
|
assertOperatorDeptRelatedToTarget(user.getDeptId());
|
||||||
|
runWithLock(user.getId(), () -> deptUserScoreTransferTxService.transferIssue(request));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reclaimDeptScore(AiUserDeptScoreRequest request) {
|
||||||
|
AiUser user = loadUserForDeptOp(request.getUserId());
|
||||||
|
assertOperatorDeptRelatedToTarget(user.getDeptId());
|
||||||
|
runWithLock(user.getId(), () -> deptUserScoreTransferTxService.transferReclaim(request));
|
||||||
|
}
|
||||||
|
|
||||||
|
private AiUser loadUserForDeptOp(Long id) {
|
||||||
|
AiUser user = aiUserService.selectAiUserById(id);
|
||||||
|
if (user == null) {
|
||||||
|
throw new ServiceException("用户不存在");
|
||||||
|
}
|
||||||
|
if (user.getDeptId() == null) {
|
||||||
|
throw new ServiceException("用户未分配部门,无法操作");
|
||||||
|
}
|
||||||
|
if (user.getDelFlag() != null && !"0".equals(user.getDelFlag())) {
|
||||||
|
throw new ServiceException("用户已删除或无效");
|
||||||
|
}
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前登录用户部门与目标用户部门须相同,或一方在另一方祖级链上(上下级)。
|
||||||
|
* 超级管理员不校验部门。
|
||||||
|
*/
|
||||||
|
private void assertOperatorDeptRelatedToTarget(Long targetUserDeptId) {
|
||||||
|
if (SecurityUtils.isAdmin(SecurityUtils.getUserId())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Long operatorDeptId = SecurityUtils.getDeptId();
|
||||||
|
if (operatorDeptId == null) {
|
||||||
|
throw new ServiceException("当前账号无归属部门,无法操作");
|
||||||
|
}
|
||||||
|
if (targetUserDeptId == null) {
|
||||||
|
throw new ServiceException("用户未分配部门,无法操作");
|
||||||
|
}
|
||||||
|
if (operatorDeptId.equals(targetUserDeptId)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SysDept targetDept = deptService.selectDeptById(targetUserDeptId);
|
||||||
|
SysDept operatorDept = deptService.selectDeptById(operatorDeptId);
|
||||||
|
if (targetDept == null || operatorDept == null) {
|
||||||
|
throw new ServiceException("部门数据异常");
|
||||||
|
}
|
||||||
|
// 目标部门在操作者部门之下,或操作者部门在目标部门之下
|
||||||
|
if (ancestorsChainContainsDeptId(targetDept.getAncestors(), operatorDeptId)
|
||||||
|
|| ancestorsChainContainsDeptId(operatorDept.getAncestors(), targetUserDeptId)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw new ServiceException("仅可操作与本部门相同或存在上下级关系的部门用户");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断 {@code ancestors}(逗号分隔祖级 id)中是否包含 {@code deptId}(含与自身部门 id 一致的场景由调用方先处理)。
|
||||||
|
*/
|
||||||
|
private static boolean ancestorsChainContainsDeptId(String ancestors, Long deptId) {
|
||||||
|
if (deptId == null || StringUtils.isEmpty(ancestors)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String needle = String.valueOf(deptId);
|
||||||
|
for (String segment : ancestors.split(",")) {
|
||||||
|
if (needle.equals(segment.trim())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void runWithLock(Long userId, Runnable inLock) {
|
||||||
|
String key = USER_LOCK_PREFIX + userId;
|
||||||
|
RLock lock = redissonClient.getLock(key);
|
||||||
|
boolean locked = false;
|
||||||
|
try {
|
||||||
|
locked = lock.tryLock(LOCK_WAIT_SECONDS, LOCK_LEASE_SECONDS, TimeUnit.SECONDS);
|
||||||
|
if (!locked) {
|
||||||
|
throw new ServiceException("系统繁忙,请稍后再试");
|
||||||
|
}
|
||||||
|
inLock.run();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
throw new ServiceException("操作被中断");
|
||||||
|
} finally {
|
||||||
|
if (locked && lock.isHeldByCurrentThread()) {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,149 @@
|
||||||
|
package com.ruoyi.ai.service.impl;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import com.ruoyi.ai.domain.AiGroupBalanceChangeRecord;
|
||||||
|
import com.ruoyi.ai.mapper.AiOrderMapper;
|
||||||
|
import com.ruoyi.ai.service.IAiGroupBalanceChangeRecordService;
|
||||||
|
import com.ruoyi.ai.service.IAiUserService;
|
||||||
|
import com.ruoyi.common.constant.BalanceChangerConstants;
|
||||||
|
import com.ruoyi.common.core.domain.entity.AiUser;
|
||||||
|
import com.ruoyi.common.core.domain.entity.SysDept;
|
||||||
|
import com.ruoyi.common.core.request.ai.AiUserDeptScoreRequest;
|
||||||
|
import com.ruoyi.common.enums.GroupBalanceChangeType;
|
||||||
|
import com.ruoyi.common.exception.ServiceException;
|
||||||
|
import com.ruoyi.common.utils.DateUtils;
|
||||||
|
import com.ruoyi.common.utils.SecurityUtils;
|
||||||
|
import com.ruoyi.common.utils.StringUtils;
|
||||||
|
import com.ruoyi.system.service.ISysDeptService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部门与用户积分互转的事务内逻辑(由门面在 Redisson 锁内调用)。
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class DeptUserScoreTransferTxService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISysDeptService deptService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IAiUserService aiUserService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IAiGroupBalanceChangeRecordService aiGroupBalanceChangeRecordService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private AiOrderMapper aiOrderMapper;
|
||||||
|
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void transferIssue(AiUserDeptScoreRequest request) {
|
||||||
|
AiUser user = requireUserWithDept(request.getUserId());
|
||||||
|
Long deptId = user.getDeptId();
|
||||||
|
BigDecimal amount = toAmountBigDecimal(request.getAmount());
|
||||||
|
String orderNum = buildOrderNum();
|
||||||
|
String remark = buildRemark(request.getRemark(), "部门下放积分至用户");
|
||||||
|
|
||||||
|
int rows = deptService.subtractDeptBalance(deptId, amount);
|
||||||
|
if (rows == 0) {
|
||||||
|
throw new ServiceException("部门积分不足或部门不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
aiUserService.addUserBalance(orderNum, user.getId(), amount, BalanceChangerConstants.DEPT_SCORE_ISSUE, remark);
|
||||||
|
|
||||||
|
BigDecimal deptBalAfter = getDeptBalance(deptId);
|
||||||
|
insertGroupRecord(orderNum, deptId, GroupBalanceChangeType.ISSUE.getCode(), amount.negate(), deptBalAfter, remark);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void transferReclaim(AiUserDeptScoreRequest request) {
|
||||||
|
AiUser user = requireUserWithDept(request.getUserId());
|
||||||
|
Long deptId = user.getDeptId();
|
||||||
|
BigDecimal amount = toAmountBigDecimal(request.getAmount());
|
||||||
|
|
||||||
|
int openCnt = aiOrderMapper.countOpenOrdersByUserId(user.getId());
|
||||||
|
if (openCnt > 0) {
|
||||||
|
throw new ServiceException("存在未完结订单,无法回收积分");
|
||||||
|
}
|
||||||
|
|
||||||
|
BigDecimal userBal = user.getBalance() == null ? BigDecimal.ZERO : user.getBalance();
|
||||||
|
if (userBal.compareTo(amount) < 0) {
|
||||||
|
throw new ServiceException("用户积分不足");
|
||||||
|
}
|
||||||
|
|
||||||
|
String orderNum = buildOrderNum();
|
||||||
|
String remark = buildRemark(request.getRemark(), "用户积分回收至部门");
|
||||||
|
|
||||||
|
aiUserService.addUserBalance(orderNum, user.getId(), amount.negate(), BalanceChangerConstants.DEPT_SCORE_RECLAIM, remark);
|
||||||
|
|
||||||
|
int rows = deptService.addDeptBalance(deptId, amount);
|
||||||
|
if (rows == 0) {
|
||||||
|
throw new ServiceException("部门不存在或已删除");
|
||||||
|
}
|
||||||
|
|
||||||
|
BigDecimal deptBalAfter = getDeptBalance(deptId);
|
||||||
|
insertGroupRecord(orderNum, deptId, GroupBalanceChangeType.RECLAIM.getCode(), amount, deptBalAfter, remark);
|
||||||
|
}
|
||||||
|
|
||||||
|
private AiUser requireUserWithDept(Long id) {
|
||||||
|
AiUser user = aiUserService.selectAiUserById(id);
|
||||||
|
if (user == null) {
|
||||||
|
throw new ServiceException("用户不存在");
|
||||||
|
}
|
||||||
|
if (user.getDeptId() == null) {
|
||||||
|
throw new ServiceException("用户未分配部门,无法操作");
|
||||||
|
}
|
||||||
|
if (user.getDelFlag() != null && !"0".equals(user.getDelFlag())) {
|
||||||
|
throw new ServiceException("用户已删除或无效");
|
||||||
|
}
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 请求为整数积分,与库表 decimal 对接(无小数) */
|
||||||
|
private static BigDecimal toAmountBigDecimal(Long amount) {
|
||||||
|
if (amount == null || amount < 1) {
|
||||||
|
throw new ServiceException("积分必须为正整数");
|
||||||
|
}
|
||||||
|
return BigDecimal.valueOf(amount.longValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
private String buildRemark(String input, String defaultPrefix) {
|
||||||
|
if (StringUtils.isNotEmpty(input)) {
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
return defaultPrefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
private BigDecimal getDeptBalance(Long deptId) {
|
||||||
|
SysDept dept = deptService.selectDeptById(deptId);
|
||||||
|
if (dept == null) {
|
||||||
|
throw new ServiceException("部门不存在");
|
||||||
|
}
|
||||||
|
return dept.getBalance() == null ? BigDecimal.ZERO : dept.getBalance();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void insertGroupRecord(String orderNum, Long deptId, int type, BigDecimal signedChange,
|
||||||
|
BigDecimal resultBalance, String remark) {
|
||||||
|
AiGroupBalanceChangeRecord record = new AiGroupBalanceChangeRecord();
|
||||||
|
record.setRelationOrderNo(orderNum);
|
||||||
|
record.setDeptId(deptId);
|
||||||
|
record.setType(type);
|
||||||
|
record.setChangeAmount(signedChange);
|
||||||
|
record.setResultAmount(resultBalance);
|
||||||
|
record.setRemark(remark);
|
||||||
|
record.setCreateBy(SecurityUtils.getUserId());
|
||||||
|
aiGroupBalanceChangeRecordService.insert(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String buildOrderNum() {
|
||||||
|
String uuid = UUID.randomUUID().toString().replace("-", "").substring(0, 8);
|
||||||
|
String dateTime = new SimpleDateFormat("yyyyMMdd").format(new Date());
|
||||||
|
return "DU" + dateTime + uuid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -173,4 +173,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
#{id}
|
#{id}
|
||||||
</foreach>
|
</foreach>
|
||||||
</delete>
|
</delete>
|
||||||
|
|
||||||
|
<select id="countOpenOrdersByUserId" resultType="int">
|
||||||
|
select count(1) from ai_order
|
||||||
|
where user_id = #{userId}
|
||||||
|
and del_flag = '0'
|
||||||
|
and status=0
|
||||||
|
</select>
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
-- =============================================================================
|
||||||
|
-- AI用户管理 下级权限:下放积分、回收积分(菜单类型 F,挂在「AI用户管理」下)
|
||||||
|
-- 仅拥有对应 perms 的角色在页面可看到按钮(v-hasPermi)
|
||||||
|
-- 可重复执行:已存在相同 perms 时跳过插入
|
||||||
|
-- =============================================================================
|
||||||
|
|
||||||
|
-- 父菜单:AI用户管理(C 菜单,component 一般为 ai/user/index)
|
||||||
|
SET @ai_user_menu_id := (
|
||||||
|
SELECT menu_id FROM sys_menu
|
||||||
|
WHERE menu_type = 'C'
|
||||||
|
AND (perms = 'ai:user:list' OR perms LIKE 'ai:user:list')
|
||||||
|
AND (path = 'aiUser' OR component = 'ai/user/index' OR component LIKE '%ai/user/index%')
|
||||||
|
ORDER BY menu_id
|
||||||
|
LIMIT 1
|
||||||
|
);
|
||||||
|
|
||||||
|
-- 若未找到父菜单,后续 INSERT 会失败,请先核对 sys_menu 中 AI 用户页配置
|
||||||
|
INSERT INTO sys_menu (
|
||||||
|
menu_name, parent_id, order_num, path, component, `query`, route_name,
|
||||||
|
is_frame, is_cache, menu_type, visible, status, perms, icon,
|
||||||
|
create_by, create_time, remark
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
'下放积分', @ai_user_menu_id, 1, '', '', NULL, '',
|
||||||
|
1, 0, 'F', '0', '0', 'ai:user:deptScoreIssue', '#',
|
||||||
|
'admin', NOW(), '部门积分下放至用户(sys_dept.balance → ai_user.balance)'
|
||||||
|
FROM (SELECT 1) AS _x
|
||||||
|
WHERE @ai_user_menu_id IS NOT NULL
|
||||||
|
AND NOT EXISTS (SELECT 1 FROM sys_menu WHERE perms = 'ai:user:deptScoreIssue');
|
||||||
|
|
||||||
|
INSERT INTO sys_menu (
|
||||||
|
menu_name, parent_id, order_num, path, component, `query`, route_name,
|
||||||
|
is_frame, is_cache, menu_type, visible, status, perms, icon,
|
||||||
|
create_by, create_time, remark
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
'回收积分', @ai_user_menu_id, 2, '', '', NULL, '',
|
||||||
|
1, 0, 'F', '0', '0', 'ai:user:deptScoreReclaim', '#',
|
||||||
|
'admin', NOW(), '用户积分回收至部门(需无未完结订单)'
|
||||||
|
FROM (SELECT 1) AS _y
|
||||||
|
WHERE @ai_user_menu_id IS NOT NULL
|
||||||
|
AND NOT EXISTS (SELECT 1 FROM sys_menu WHERE perms = 'ai:user:deptScoreReclaim');
|
||||||
|
|
||||||
|
-- 已勾选「AI用户管理」菜单的角色,自动勾选上述两个按钮(避免角色树里看不到或未授权)
|
||||||
|
INSERT INTO sys_role_menu (role_id, menu_id)
|
||||||
|
SELECT DISTINCT rm.role_id, m.menu_id
|
||||||
|
FROM sys_role_menu rm
|
||||||
|
JOIN sys_menu m ON m.perms = 'ai:user:deptScoreIssue'
|
||||||
|
WHERE rm.menu_id = @ai_user_menu_id
|
||||||
|
AND NOT EXISTS (
|
||||||
|
SELECT 1 FROM sys_role_menu x WHERE x.role_id = rm.role_id AND x.menu_id = m.menu_id
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO sys_role_menu (role_id, menu_id)
|
||||||
|
SELECT DISTINCT rm.role_id, m.menu_id
|
||||||
|
FROM sys_role_menu rm
|
||||||
|
JOIN sys_menu m ON m.perms = 'ai:user:deptScoreReclaim'
|
||||||
|
WHERE rm.menu_id = @ai_user_menu_id
|
||||||
|
AND NOT EXISTS (
|
||||||
|
SELECT 1 FROM sys_role_menu x WHERE x.role_id = rm.role_id AND x.menu_id = m.menu_id
|
||||||
|
);
|
||||||
|
|
@ -4676,6 +4676,9 @@ INSERT INTO `sys_menu` VALUES (2001, 'AI用户管理', 2003, 1, 'aiUser', 'ai/us
|
||||||
INSERT INTO `sys_menu` VALUES (2002, 'AI管理', 2000, 4, 'aiManager', 'ai/manager/index', NULL, '', 1, 0, 'C', '0', '0', 'ai:manager:list', 'online', 'admin', '2025-11-13 19:18:54', 'admin', '2025-11-13 22:49:28', '');
|
INSERT INTO `sys_menu` VALUES (2002, 'AI管理', 2000, 4, 'aiManager', 'ai/manager/index', NULL, '', 1, 0, 'C', '0', '0', 'ai:manager:list', 'online', 'admin', '2025-11-13 19:18:54', 'admin', '2025-11-13 22:49:28', '');
|
||||||
INSERT INTO `sys_menu` VALUES (2003, '用户管理', 2000, 1, 'aiUserManger', NULL, NULL, '', 1, 0, 'M', '0', '0', NULL, 'peoples', 'admin', '2025-11-13 22:18:42', '', NULL, '');
|
INSERT INTO `sys_menu` VALUES (2003, '用户管理', 2000, 1, 'aiUserManger', NULL, NULL, '', 1, 0, 'M', '0', '0', NULL, 'peoples', 'admin', '2025-11-13 22:18:42', '', NULL, '');
|
||||||
INSERT INTO `sys_menu` VALUES (2004, '余额使用记录', 2003, 2, 'balanceChangeRecord', 'ai/balanceChangeRecord/index', NULL, '', 1, 0, 'C', '0', '0', 'ai:balanceChangeRecord:list', 'nested', 'admin', '2025-11-13 22:31:42', '', NULL, '');
|
INSERT INTO `sys_menu` VALUES (2004, '余额使用记录', 2003, 2, 'balanceChangeRecord', 'ai/balanceChangeRecord/index', NULL, '', 1, 0, 'C', '0', '0', 'ai:balanceChangeRecord:list', 'nested', 'admin', '2025-11-13 22:31:42', '', NULL, '');
|
||||||
|
-- AI用户管理(2001)下级按钮:下放/回收积分(权限 ai:user:deptScoreIssue / ai:user:deptScoreReclaim);已存在时可跳过或执行 sql/ai_user_dept_score_menu.sql
|
||||||
|
INSERT INTO `sys_menu` VALUES (2070, '下放积分', 2001, 3, '', '', NULL, '', 1, 0, 'F', '0', '0', 'ai:user:deptScoreIssue', '#', 'admin', '2025-11-13 22:31:42', '', NULL, '部门积分下放至用户');
|
||||||
|
INSERT INTO `sys_menu` VALUES (2071, '回收积分', 2001, 4, '', '', NULL, '', 1, 0, 'F', '0', '0', 'ai:user:deptScoreReclaim', '#', 'admin', '2025-11-13 22:31:42', '', NULL, '用户积分回收至部门');
|
||||||
INSERT INTO `sys_menu` VALUES (2005, '返佣记录', 2003, 2, 'rebateRecord', 'ai/rebateRecord/index', NULL, '', 1, 0, 'C', '0', '0', 'ai:rebateRecord:list', 'monitor', 'admin', '2025-11-13 22:32:39', '', NULL, '');
|
INSERT INTO `sys_menu` VALUES (2005, '返佣记录', 2003, 2, 'rebateRecord', 'ai/rebateRecord/index', NULL, '', 1, 0, 'C', '0', '0', 'ai:rebateRecord:list', 'monitor', 'admin', '2025-11-13 22:32:39', '', NULL, '');
|
||||||
INSERT INTO `sys_menu` VALUES (2006, '订单记录', 2000, 5, 'order', 'ai/order/index', NULL, '', 1, 0, 'C', '0', '0', 'ai:order:list', 'server', 'admin', '2025-11-13 22:36:36', 'admin', '2025-11-29 16:12:14', '');
|
INSERT INTO `sys_menu` VALUES (2006, '订单记录', 2000, 5, 'order', 'ai/order/index', NULL, '', 1, 0, 'C', '0', '0', 'ai:order:list', 'server', 'admin', '2025-11-13 22:36:36', 'admin', '2025-11-29 16:12:14', '');
|
||||||
INSERT INTO `sys_menu` VALUES (2007, '充值记录', 2000, 6, 'recharge', 'ai/recharge/index', NULL, '', 1, 0, 'C', '0', '0', 'ai:recharge:list', 'number', 'admin', '2025-11-13 22:38:06', 'admin', '2025-11-13 22:50:05', '');
|
INSERT INTO `sys_menu` VALUES (2007, '充值记录', 2000, 6, 'recharge', 'ai/recharge/index', NULL, '', 1, 0, 'C', '0', '0', 'ai:recharge:list', 'number', 'admin', '2025-11-13 22:38:06', 'admin', '2025-11-13 22:50:05', '');
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue