fix:新功能提交

This commit is contained in:
old burden 2026-04-20 17:10:16 +08:00
parent 009886d9d8
commit 7177d7c404
38 changed files with 1537 additions and 848 deletions

View File

@ -0,0 +1,44 @@
import request from '@/utils/request'
// 查询团队(部门)对应火山引擎配置列表
export function listConfig(query) {
return request({
url: '/ai/config/list',
method: 'get',
params: query
})
}
// 查询团队(部门)对应火山引擎配置详细
export function getConfig(id) {
return request({
url: '/ai/config/' + id,
method: 'get'
})
}
// 新增团队(部门)对应火山引擎配置
export function addConfig(data) {
return request({
url: '/ai/config',
method: 'post',
data: data
})
}
// 修改团队(部门)对应火山引擎配置
export function updateConfig(data) {
return request({
url: '/ai/config',
method: 'put',
data: data
})
}
// 删除团队(部门)对应火山引擎配置
export function delConfig(id) {
return request({
url: '/ai/config/' + id,
method: 'delete'
})
}

View File

@ -0,0 +1,10 @@
import request from '@/utils/request'
// 查询团队每日消耗统计
export function listData(query) {
return request({
url: '/ai/data/list',
method: 'get',
params: query
})
}

View File

@ -0,0 +1,44 @@
import request from '@/utils/request'
// 查询团队(部门)余额变动列表
export function listRecord(query) {
return request({
url: '/ai/record/list',
method: 'get',
params: query
})
}
// 查询团队(部门)余额变动详细
export function getRecord(id) {
return request({
url: '/ai/record/' + id,
method: 'get'
})
}
// 新增团队(部门)余额变动
export function addRecord(data) {
return request({
url: '/ai/record',
method: 'post',
data: data
})
}
// 修改团队(部门)余额变动
export function updateRecord(data) {
return request({
url: '/ai/record',
method: 'put',
data: data
})
}
// 删除团队(部门)余额变动
export function delRecord(id) {
return request({
url: '/ai/record/' + id,
method: 'delete'
})
}

View File

@ -0,0 +1,70 @@
import request from '@/utils/request'
export function getSubteamOverview() {
return request({ url: '/subteam/overview', method: 'get' })
}
export function listSubteamUser(query) {
return request({ url: '/subteam/user/list', method: 'get', params: query })
}
export function getSubteamUser(id) {
const url = id != null && id !== '' ? '/subteam/user/' + id : '/subteam/user'
return request({ url, method: 'get' })
}
export function addSubteamUser(data) {
return request({ url: '/subteam/user', method: 'post', data })
}
export function updateSubteamUser(data) {
return request({ url: '/subteam/user', method: 'put', data })
}
export function delSubteamUser(userIds) {
return request({ url: '/subteam/user/' + userIds, method: 'delete' })
}
export function resetSubteamUserPwd(data) {
return request({ url: '/subteam/user/resetPwd', method: 'put', data })
}
export function changeSubteamUserStatus(data) {
return request({ url: '/subteam/user/changeStatus', method: 'put', data })
}
export function listSubteamVideoOrder(query) {
return request({ url: '/subteam/video-order/list', method: 'get', params: query })
}
export function getSubteamVideoOrder(id) {
return request({ url: '/subteam/video-order/' + id, method: 'get' })
}
export function listSubteamChargeOrder(query) {
return request({ url: '/subteam/charge-order/list', method: 'get', params: query })
}
export function getSubteamChargeOrder(id) {
return request({ url: '/subteam/charge-order/' + id, method: 'get' })
}
export function listSubteamUserBalance(query) {
return request({ url: '/subteam/user-balance/list', method: 'get', params: query })
}
export function getSubteamUserBalance(id) {
return request({ url: '/subteam/user-balance/' + id, method: 'get' })
}
export function listSubteamConsumeStat(query) {
return request({ url: '/subteam/consume-stat/list', method: 'get', params: query })
}
export function listSubteamGroupBalance(query) {
return request({ url: '/subteam/group-balance/list', method: 'get', params: query })
}
export function getSubteamGroupBalance(id) {
return request({ url: '/subteam/group-balance/' + id, method: 'get' })
}

View File

@ -0,0 +1,112 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="96px">
<el-form-item label="日期" prop="statDate">
<el-date-picker
v-model="queryParams.statDate"
type="date"
value-format="yyyyMMdd"
placeholder="请选择日期"
clearable
/>
</el-form-item>
<el-form-item label="团队名称" prop="deptName">
<el-input
v-model="queryParams.deptName"
placeholder="请输入团队名称"
clearable
@keyup.enter.native="handleQuery"
/>
</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">
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="dataList">
<el-table-column label="日期" align="center" prop="dateKey" />
<el-table-column label="团队名称" align="center" prop="deptName" />
<el-table-column label="实际充值积分(充值-退款)" align="center" prop="rechargeScore" />
<el-table-column label="消耗积分" align="center" prop="score" />
<el-table-column label="实际订单数量(成功)" align="center" prop="orderCount" />
<el-table-column label="三方消耗tokens数量" align="center" prop="useTokens" />
</el-table>
<pagination
v-show="total>0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
</div>
</template>
<script>
import { listData } from "@/api/ai/data"
export default {
name: "TeamConsumeData",
data() {
return {
//
loading: true,
//
showSearch: true,
//
total: 0,
//
dataList: [],
//
searched: false,
//
queryParams: {
pageNum: 1,
pageSize: 10,
statDate: null,
deptName: null
},
}
},
methods: {
/** 查询团队每日消耗统计列表 */
getList() {
if (!this.searched) {
this.loading = false
this.dataList = []
this.total = 0
return
}
this.loading = true
listData(this.queryParams).then(response => {
this.dataList = response.rows
this.total = response.total
this.loading = false
})
},
/** 搜索按钮操作 */
handleQuery() {
if (!this.queryParams.statDate || !this.queryParams.deptName) {
this.$modal.msgWarning("请先填写日期和团队名称后再搜索")
return
}
this.searched = true
this.queryParams.pageNum = 1
this.getList()
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm")
this.searched = false
this.dataList = []
this.total = 0
}
}
}
</script>

View File

@ -34,7 +34,7 @@
size="mini"
@click="handleAdd"
v-hasPermi="['system:dept:add']"
>新增</el-button>
>新增二级部门</el-button>
</el-col>
<el-col :span="1.5">
<el-button
@ -57,10 +57,10 @@
:tree-props="{children: 'children', hasChildren: 'hasChildren'}"
>
<el-table-column prop="deptName" label="部门名称" width="260"></el-table-column>
<el-table-column prop="orderNum" label="排序" width="80"></el-table-column>
<el-table-column prop="balance" label="剩余积分" width="200" align="right">
<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.balance != null ? scope.row.balance : '—' }}</span>
<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">
@ -68,20 +68,13 @@
<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="150">
<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
size="mini"
type="text"
icon="el-icon-plus"
@click="handleAdd(scope.row)"
v-hasPermi="['system:dept:add']"
>新增</el-button>
<el-button
size="mini"
type="text"
@ -89,6 +82,14 @@
@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"
@ -97,20 +98,6 @@
@click="handleDelete(scope.row)"
v-hasPermi="['system:dept:remove']"
>删除</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-wallet"
@click="handleChargeRefund(scope.row)"
v-hasPermi="['system:dept:chargeRefund']"
>充值/退款</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-s-operation"
@click="handleEditScore(scope.row)"
v-hasPermi="['system:dept:chargeRefund']"
>积分更正</el-button>
</template>
</el-table-column>
</el-table>
@ -133,31 +120,31 @@
</el-col>
<el-col :span="12">
<el-form-item label="显示排序" prop="orderNum">
<el-input-number v-model="form.orderNum" controls-position="right" :min="0" />
<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" />
<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" />
<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" />
<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">
<el-radio-group v-model="form.status" :disabled="isFirstLevelEditForm">
<el-radio
v-for="dict in dict.type.sys_normal_disable"
:key="dict.value"
@ -167,6 +154,25 @@
</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">限制本部门下启用状态账号数量0 或不填表示不限制</p>
</el-col>
</el-row>
<el-row v-if="isSecondLevelCompanyForm">
<el-col :span="24">
<el-form-item label="Byte API Key">
@ -230,95 +236,11 @@
</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="'充值/退款 — ' + (chargeRefundForm.deptName || '')"
:visible.sync="chargeRefundOpen"
width="520px"
append-to-body
@close="resetChargeRefund"
>
<el-form ref="chargeRefundFormRef" :model="chargeRefundForm" :rules="chargeRefundRules" label-width="88px">
<el-form-item label="类型" prop="orderType">
<el-radio-group v-model="chargeRefundForm.orderType">
<el-radio :label="0">充值</el-radio>
<el-radio :label="1">退款</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="金额" prop="money">
<el-input
:value="chargeRefundMoneyDisplay"
placeholder="财务记录(元),如 9,999,999.00"
clearable
@input="onChargeRefundMoneyInput"
@blur="onChargeRefundMoneyBlur"
/>
</el-form-item>
<el-form-item label="积分" prop="amount">
<el-input
:value="chargeRefundAmountDisplay"
placeholder="变动积分,如 99,999,999"
clearable
@input="onChargeRefundAmountInput"
/>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input
v-model="chargeRefundForm.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="submitChargeRefund"> </el-button>
<el-button @click="chargeRefundOpen = false"> </el-button>
</div>
</el-dialog>
<el-dialog
:title="'积分更正 — ' + (editScoreForm.deptName || '')"
:visible.sync="editScoreOpen"
width="520px"
append-to-body
@close="resetEditScore"
>
<el-form ref="editScoreFormRef" :model="editScoreForm" :rules="editScoreRules" label-width="88px">
<el-form-item label="积分" prop="score">
<el-input-number
v-model="editScoreForm.score"
:precision="0"
:step="1"
:min="-100000000"
:max="100000000"
controls-position="right"
class="edit-score-input-number"
placeholder="正数增加负数扣减不能为0"
/>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input
v-model="editScoreForm.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="submitEditScore"> </el-button>
<el-button @click="editScoreOpen = false"> </el-button>
</div>
</el-dialog>
</div>
</template>
@ -345,23 +267,15 @@
color: #909399;
line-height: 1.5;
}
.edit-score-input-number {
width: 100%;
.form-tip {
margin-right: 16px;
color: #e6a23c;
font-size: 12px;
}
</style>
<script>
import { listDept, getDept, delDept, addDept, updateDept, listDeptExcludeChild, chargeRefundDept, editScore } from "@/api/system/dept"
import {
WESTERN_MONEY_MAX,
sanitizeMoneyDigits,
formatMoneyWesternDisplay,
moneyStringToNumber,
formatMoneyWesternFinal,
sanitizeIntDigits,
formatIntWesternDisplay,
intStringToNumber
} from "@/utils/westernNumberFormat"
import { listDept, getDept, delDept, addDept, updateDept, listDeptExcludeChild } from "@/api/system/dept"
import Treeselect from "@riophae/vue-treeselect"
import "@riophae/vue-treeselect/dist/vue-treeselect.css"
@ -394,76 +308,8 @@ export default {
},
//
form: {},
originalForm: {},
modelParamRows: [{ label: '', value: '' }],
chargeRefundOpen: false,
chargeRefundMoneyDisplay: "",
chargeRefundAmountDisplay: "",
chargeRefundForm: {
deptId: undefined,
deptName: "",
orderType: 0,
money: undefined,
amount: undefined,
remark: ""
},
chargeRefundRules: {
orderType: [
{ required: true, message: "类型不能为空", trigger: "change" }
],
money: [
{ required: true, message: "金额不能为空", trigger: "blur" },
{ type: "number", min: 0, max: 10000000, message: "金额须在 010000000 之间", trigger: "blur" }
],
amount: [
{ required: true, message: "积分不能为空", trigger: "blur" },
{ type: "number", min: 1, max: 100000000, message: "积分须在 1100000000 之间", trigger: "blur" }
],
remark: [
{ max: 50, message: "备注不能超过50个字符", trigger: "blur" }
]
},
editScoreOpen: false,
editScoreForm: {
deptId: undefined,
deptName: "",
score: undefined,
remark: ""
},
editScoreRules: {
score: [
{ required: true, message: "积分不能为空", trigger: "blur" },
{
validator(rule, value, callback) {
if (value === undefined || value === null || value === "") {
callback(new Error("积分不能为空"))
} else if (!Number.isInteger(Number(value))) {
callback(new Error("积分须为整数"))
} else if (Number(value) === 0) {
callback(new Error("积分不能为0"))
} else if (Number(value) < -100000000 || Number(value) > 100000000) {
callback(new Error("积分须在 -100000000100000000 之间不含0"))
} else {
callback()
}
},
trigger: "blur"
}
],
remark: [
{ required: true, message: "备注不能为空", trigger: "blur" },
{
validator(rule, value, callback) {
if (!value || String(value).trim() === "") {
callback(new Error("备注不能为空"))
} else {
callback()
}
},
trigger: "blur"
},
{ max: 50, message: "备注不能超过50个字符", trigger: "blur" }
]
},
//
rules: {
parentId: [
@ -506,9 +352,35 @@ export default {
return true
}
return false
},
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
})
},
syncModelRowsFromForm() {
this.modelParamRows = [{ label: '', value: '' }]
const raw = this.form.modelParm
@ -578,11 +450,13 @@ export default {
leader: undefined,
phone: undefined,
email: undefined,
maxUserCount: undefined,
byteApiKey: undefined,
project: undefined,
modelParm: undefined,
status: "0"
}
this.originalForm = {}
this.modelParamRows = [{ label: '', value: '' }]
this.resetForm("form")
},
@ -598,13 +472,17 @@ export default {
/** 新增按钮操作 */
handleAdd(row) {
this.reset()
if (row != undefined) {
if (row !== undefined) {
if (!this.isFirstLevelRow(row)) {
this.$modal.msgError("仅允许在一级部门下新增二级部门")
return
}
this.form.parentId = row.deptId
}
this.open = true
this.title = "添加部门"
this.title = "添加二级部门"
listDept().then(response => {
this.deptOptions = this.handleTree(response.data, "deptId")
this.deptOptions = this.getFirstLevelDeptOptions(this.handleTree(response.data, "deptId"))
})
},
/** 展开/折叠操作 */
@ -620,11 +498,13 @@ export default {
this.reset()
getDept(row.deptId).then(response => {
this.form = response.data
this.originalForm = { ...response.data }
this.syncModelRowsFromForm()
this.open = true
this.title = "修改部门"
listDeptExcludeChild(row.deptId).then(response => {
this.deptOptions = this.handleTree(response.data, "deptId")
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)
@ -637,7 +517,24 @@ export default {
this.$refs["form"].validate(valid => {
if (valid) {
this.buildModelParmPayload()
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
this.form.byteApiKey = oldDept.byteApiKey
this.form.project = oldDept.project
this.form.modelParm = oldDept.modelParm
}
updateDept(this.form).then(response => {
this.$modal.msgSuccess("修改成功")
this.open = false
@ -653,132 +550,6 @@ export default {
}
})
},
resetChargeRefund() {
this.chargeRefundMoneyDisplay = ""
this.chargeRefundAmountDisplay = ""
this.chargeRefundForm = {
deptId: undefined,
deptName: "",
orderType: 0,
money: undefined,
amount: undefined,
remark: ""
}
this.$nextTick(() => {
if (this.$refs.chargeRefundFormRef) {
this.$refs.chargeRefundFormRef.clearValidate()
}
})
},
handleChargeRefund(row) {
this.chargeRefundMoneyDisplay = ""
this.chargeRefundAmountDisplay = ""
this.chargeRefundForm = {
deptId: row.deptId,
deptName: row.deptName,
orderType: 0,
money: undefined,
amount: undefined,
remark: ""
}
this.chargeRefundOpen = true
this.$nextTick(() => {
if (this.$refs.chargeRefundFormRef) {
this.$refs.chargeRefundFormRef.clearValidate()
}
})
},
onChargeRefundMoneyInput(val) {
const sanitized = sanitizeMoneyDigits(val)
if (!sanitized) {
this.chargeRefundMoneyDisplay = ""
this.chargeRefundForm.money = undefined
return
}
const raw = parseFloat(sanitized)
if (!isNaN(raw) && raw > WESTERN_MONEY_MAX) {
this.chargeRefundForm.money = WESTERN_MONEY_MAX
this.chargeRefundMoneyDisplay = formatMoneyWesternFinal(WESTERN_MONEY_MAX)
return
}
this.chargeRefundMoneyDisplay = formatMoneyWesternDisplay(sanitized)
this.chargeRefundForm.money = moneyStringToNumber(sanitized)
},
onChargeRefundMoneyBlur() {
if (this.chargeRefundForm.money !== undefined && this.chargeRefundForm.money !== null) {
this.chargeRefundMoneyDisplay = formatMoneyWesternFinal(this.chargeRefundForm.money)
}
},
onChargeRefundAmountInput(val) {
const digits = sanitizeIntDigits(val)
this.chargeRefundAmountDisplay = digits === "" ? "" : formatIntWesternDisplay(digits)
this.chargeRefundForm.amount = intStringToNumber(digits)
},
submitChargeRefund() {
this.onChargeRefundMoneyBlur()
this.$refs["chargeRefundFormRef"].validate(valid => {
if (!valid) {
return
}
const data = {
deptId: this.chargeRefundForm.deptId,
orderType: this.chargeRefundForm.orderType,
money: this.chargeRefundForm.money,
amount: this.chargeRefundForm.amount,
remark: this.chargeRefundForm.remark ? this.chargeRefundForm.remark.trim() : undefined
}
chargeRefundDept(data).then(() => {
this.$modal.msgSuccess("操作成功")
this.chargeRefundOpen = false
this.getList()
})
})
},
resetEditScore() {
this.editScoreForm = {
deptId: undefined,
deptName: "",
score: undefined,
remark: ""
}
this.$nextTick(() => {
if (this.$refs.editScoreFormRef) {
this.$refs.editScoreFormRef.clearValidate()
}
})
},
handleEditScore(row) {
this.editScoreForm = {
deptId: row.deptId,
deptName: row.deptName,
score: undefined,
remark: ""
}
this.editScoreOpen = true
this.$nextTick(() => {
if (this.$refs.editScoreFormRef) {
this.$refs.editScoreFormRef.clearValidate()
}
})
},
submitEditScore() {
this.$refs["editScoreFormRef"].validate(valid => {
if (!valid) {
return
}
const remark = (this.editScoreForm.remark || "").trim()
const data = {
deptId: this.editScoreForm.deptId,
score: this.editScoreForm.score,
remark: remark
}
editScore(data).then(() => {
this.$modal.msgSuccess("操作成功")
this.editScoreOpen = false
this.getList()
})
})
},
/** 删除按钮操作 */
handleDelete(row) {
this.$modal.confirm('是否确认删除名称为"' + row.deptName + '"的数据项?').then(function() {

View File

@ -44,20 +44,7 @@
inputType="password"
:placeholder="`${$t('common.passwordPlaceholder')}`" />
<div class="login-link">
<mf-button
class="grey"
type="text"
@click="showForgot">
{{ $t('common.forgotPassword') }}
</mf-button>
</div>
<div class="login-submit">
<mf-button
size="large"
@click="showRegister">
{{ $t('common.register') }}
</mf-button>
<mf-button
size="large"
type="primary"
@ -67,25 +54,10 @@
</mf-button>
</div>
</mf-dialog>
<Forgot
v-if="forgotVisible"
:visible="forgotVisible"
@open="forgotVisible = true"
@back="back"
@cancel="forgotVisible = false" />
<Register
v-if="registerVisible"
:visible="registerVisible"
@cancel="registerVisible = false"
@back="backFormRegister"
@open="registerVisible = true" />
</div>
</template>
<script>
import Forgot from './Forgot.vue'
import Register from './Register.vue'
import { mapGetters } from 'vuex'
import i18n from '@/lang/i18n'
@ -93,22 +65,16 @@ export default {
data() {
return {
email: '',
forgotVisible: false,
emailVisible: false,
registerVisible: false,
loading: false,
username: '',
password: ''
}
},
props: {
visible: Boolean,
register: Boolean
},
components: {
Forgot,
Register
visible: Boolean
},
components: {},
computed: {
...mapGetters(['lang'])
},
@ -121,10 +87,6 @@ export default {
// }
this.username = ""
this.password = ""
let { inviteCode } = this.$route.query || {}
if (inviteCode) {
this.showRegister()
}
},
methods: {
cancel() {
@ -132,24 +94,12 @@ export default {
this.password = ''
this.$emit('cancel')
},
showRegister() {
this.registerVisible = true
this.$emit('cancel')
},
changeLang(value) {
if (value != this.lang) {
this.$store.dispatch('main/setLanguage', value)
i18n.global.locale = value
}
},
back() {
this.forgotVisible = false
this.$emit('open')
},
backFormRegister() {
this.registerVisible = false
this.$emit('open')
},
login() {
if (!this.username) {
this.$message.error(this.$t('common.userEmailPlaceholder'))
@ -191,10 +141,6 @@ export default {
.catch((_) => {
this.loading = false
})
},
showForgot() {
this.forgotVisible = true
this.$emit('cancel')
}
}
}
@ -324,36 +270,8 @@ export default {
justify-content: center;
margin-top: 30px;
.mf-button {
width: 160px;
width: 220px;
border-radius: 10px;
margin: 0 14px;
&:first-child {
color: #ffffff;
background-color: #1a1a1a;
&:hover {
background-color: #262626;
}
&:active {
background-color: #0d0d0d;
}
}
}
}
.login-link {
display: flex;
justify-content: flex-end;
color: #999;
margin-top: 10px;
.mf-button {
padding: 0;
color: #fff;
font-size: 12px;
&:hover {
background-color: transparent;
}
}
}
}

View File

@ -78,7 +78,6 @@
</div>
<Login
:register="!$datas.isEmpty(inviteCode)"
:visible="showLogin"
@open="openLogin"
@cancel="cancelLogin" />
@ -118,7 +117,6 @@ export default {
}
],
publishVisible: false,
inviteCode: this.$route.query?.inviteCode,
userVisible: false,
logoUrl: null
}
@ -179,9 +177,6 @@ export default {
}
},
mounted() {
if (this.inviteCode) {
this.openLogin()
}
this.getLogo()
if (getToken()) {
this.$store.dispatch('user/getInfo').catch(() => {})

View File

@ -0,0 +1,45 @@
package com.ruoyi.web.controller.subteam;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.ai.domain.AiChargeRefundOrder;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.system.service.subteam.ISubteamDataQueryService;
import com.ruoyi.system.service.subteam.ISubteamScopeService;
import com.ruoyi.ai.service.IAiChargeRefundOrderService;
@RestController
@RequestMapping("/subteam/charge-order")
public class SubteamChargeOrderController extends BaseController {
@Autowired
private ISubteamDataQueryService subteamDataQueryService;
@Autowired
private ISubteamScopeService subteamScopeService;
@Autowired
private IAiChargeRefundOrderService aiChargeRefundOrderService;
@PreAuthorize("@ss.hasPermi('subteam:charge:list')")
@GetMapping("/list")
public TableDataInfo list(AiChargeRefundOrder query) {
startPage();
List<AiChargeRefundOrder> list = subteamDataQueryService.selectChargeRefundOrders(query);
return getDataTable(list);
}
@PreAuthorize("@ss.hasPermi('subteam:charge:query')")
@GetMapping("/{id}")
public AjaxResult getInfo(@PathVariable Long id) {
subteamScopeService.assertChargeRefundBelongsToTeam(id);
return success(aiChargeRefundOrderService.selectAiChargeRefundOrderById(id));
}
}

View File

@ -0,0 +1,32 @@
package com.ruoyi.web.controller.subteam;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.ai.domain.AiVideoReportData;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.service.subteam.ISubteamDataQueryService;
@RestController
@RequestMapping("/subteam/consume-stat")
public class SubteamConsumeStatController extends BaseController {
@Autowired
private ISubteamDataQueryService subteamDataQueryService;
@PreAuthorize("@ss.hasPermi('subteam:consume:list')")
@GetMapping("/list")
public TableDataInfo list(AiVideoReportData query) {
if (StringUtils.isEmpty(query.getStatDate())) {
return getDataTable(java.util.Collections.emptyList());
}
startPage();
List<AiVideoReportData> list = subteamDataQueryService.selectTeamDailyConsume(query.getStatDate());
return getDataTable(list);
}
}

View File

@ -0,0 +1,45 @@
package com.ruoyi.web.controller.subteam;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.ai.domain.AiGroupBalanceChangeRecord;
import com.ruoyi.ai.service.IAiGroupBalanceChangeRecordService;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.system.service.subteam.ISubteamDataQueryService;
import com.ruoyi.system.service.subteam.ISubteamScopeService;
@RestController
@RequestMapping("/subteam/group-balance")
public class SubteamGroupBalanceController extends BaseController {
@Autowired
private ISubteamDataQueryService subteamDataQueryService;
@Autowired
private ISubteamScopeService subteamScopeService;
@Autowired
private IAiGroupBalanceChangeRecordService aiGroupBalanceChangeRecordService;
@PreAuthorize("@ss.hasPermi('subteam:groupBalance:list')")
@GetMapping("/list")
public TableDataInfo list(AiGroupBalanceChangeRecord query) {
startPage();
List<AiGroupBalanceChangeRecord> list = subteamDataQueryService.selectGroupBalanceRecords(query);
return getDataTable(list);
}
@PreAuthorize("@ss.hasPermi('subteam:groupBalance:query')")
@GetMapping("/{id}")
public AjaxResult getInfo(@PathVariable String id) {
subteamScopeService.assertGroupBalanceRecordBelongsToTeam(id);
return success(aiGroupBalanceChangeRecordService.selectAiGroupBalanceChangeRecordById(id));
}
}

View File

@ -0,0 +1,26 @@
package com.ruoyi.web.controller.subteam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.system.domain.subteam.SubteamOverviewVO;
import com.ruoyi.system.service.subteam.ISubteamOverviewService;
@RestController
@RequestMapping("/subteam/overview")
public class SubteamOverviewController extends BaseController {
@Autowired
private ISubteamOverviewService subteamOverviewService;
@PreAuthorize("@ss.hasPermi('subteam:overview:view')")
@GetMapping
public AjaxResult overview() {
SubteamOverviewVO vo = subteamOverviewService.loadOverview();
return success(vo);
}
}

View File

@ -0,0 +1,45 @@
package com.ruoyi.web.controller.subteam;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.ai.domain.AiBalanceChangeRecord;
import com.ruoyi.ai.service.IAiBalanceChangeRecordService;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.system.service.subteam.ISubteamDataQueryService;
import com.ruoyi.system.service.subteam.ISubteamScopeService;
@RestController
@RequestMapping("/subteam/user-balance")
public class SubteamUserBalanceController extends BaseController {
@Autowired
private ISubteamDataQueryService subteamDataQueryService;
@Autowired
private ISubteamScopeService subteamScopeService;
@Autowired
private IAiBalanceChangeRecordService aiBalanceChangeRecordService;
@PreAuthorize("@ss.hasPermi('subteam:userBalance:list')")
@GetMapping("/list")
public TableDataInfo list(AiBalanceChangeRecord query) {
startPage();
List<AiBalanceChangeRecord> list = subteamDataQueryService.selectUserBalanceRecords(query);
return getDataTable(list);
}
@PreAuthorize("@ss.hasPermi('subteam:userBalance:query')")
@GetMapping("/{id}")
public AjaxResult getInfo(@PathVariable Long id) {
subteamScopeService.assertAiBalanceRecordVisible(id, subteamScopeService.currentTeamDeptId());
return success(aiBalanceChangeRecordService.selectAiBalanceChangeRecordById(id));
}
}

View File

@ -73,21 +73,4 @@ public class BalanceChangerConstants {
*/
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;
public static class OrderNoPrefix {
// 团队充值退款订单号前缀
public static final String RECHARGE_REFUND_PREFIX = "RE";
// 团队积分下放回收单号前缀
public static final String ISSUE_RECLAIM_PREFIX = "IS";
}
}

View File

@ -15,7 +15,7 @@
<el-form-item label="${comment}" prop="${column.javaField}">
<el-input
v-model="queryParams.${column.javaField}"
placeholder="请输入${comment}"
placeholder="请输入ID"
clearable
@keyup.enter="handleQuery"
/>

View File

@ -1,56 +1,67 @@
package com.ruoyi.ai.domain;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.annotation.Excel;
import java.math.BigDecimal;
import lombok.Data;
import com.ruoyi.common.annotation.Excel;
import com.ruoyi.common.core.domain.BaseEntity;
/**
* 充值/退款订单 ai_charge_refund_order
* 团队部门充值退款订单对象 ai_charge_refund_order
*
* @author shi
* @date 2026-04-17
*/
@Data
@TableName("ai_charge_refund_order")
public class AiChargeRefundOrder implements Serializable {
public class AiChargeRefundOrder extends BaseEntity {
private static final long serialVersionUID = 1L;
/** 主键ID */
@TableId(type = IdType.AUTO)
private Long id;
/** 删除标志0代表存在 2代表删除 */
private String delFlag;
private Long createBy;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
/** 订单编号 */
@Excel(name = "订单编号")
private String orderNum;
/** 第三方单号(预留) */
@Excel(name = "第三方单号(预留)")
private String thirdPartyOrderNum;
/** 部门ID */
@Excel(name = "部门ID")
private Long deptId;
/** 订单类型0-充值 1-退款 */
// ChargeRefundOrderType
private Integer orderType;
/** 团队名称(列表/导出关联查询,非表字段) */
@TableField(exist = false)
@Excel(name = "团队名称")
private String deptName;
/** 订单类型(0-充值;1-退款;2-手动修改) */
@Excel(name = "订单类型", readConverterExp = "0=充值,1=退款,2=手动修改")
private Long orderType;
/** 金额(元) */
@Excel(name = "金额(元)")
private BigDecimal money;
/**
* 积分变动充值/退款为绝对值退款在统计中按负数计入
* 手动修改可为正增加或负扣减
*/
@Excel(name = "积分")
private BigDecimal amount;
private String remark;
/** 状态0-进行中 1-已完成 2-失败 */
// ChargeRefundOrderStatusType
@Excel(name = "状态", readConverterExp = "0=进行中,1=已完成,2=失败")
private Integer status;
}

View File

@ -1,42 +1,44 @@
package com.ruoyi.ai.domain;
import java.io.Serializable;
import java.util.Date;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.ruoyi.common.annotation.Excel;
import com.ruoyi.common.core.domain.BaseEntity;
/**
* 部门方舟配置 ai_dept_ark_config
* 团队部门对应火山引擎配置对象 ai_dept_ark_config
*
* @author shi
* @date 2026-04-17
*/
@Data
@TableName("ai_dept_ark_config")
public class AiDeptArkConfig implements Serializable {
public class AiDeptArkConfig extends BaseEntity {
private static final long serialVersionUID = 1L;
/** $column.columnComment */
@TableId(type = IdType.AUTO)
private Long id;
private String id;
/** 部门ID */
@Excel(name = "部门ID")
private Long deptId;
/** 模型参数 JSON */
/** 视频模型列表JSON(label+value) */
@Excel(name = "视频模型列表JSON(label+value)")
private String modelParm;
/** Byte project加密 */
@Excel(name = "Byte project加密")
private String project;
/** Byte API Key加密 */
@Excel(name = "Byte API Key加密")
private String byteApiKey;
private Long createBy;
private Long updateBy;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
}

View File

@ -1,49 +1,49 @@
package com.ruoyi.ai.domain;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
import com.baomidou.mybatisplus.annotation.EnumValue;
import lombok.Data;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.annotation.Excel;
import lombok.Data;
import com.ruoyi.common.core.domain.BaseEntity;
/**
* 集团余额变动记录 ai_group_balance_change_record
* 团队部门余额变动对象 ai_group_balance_change_record
*
* @author shi
* @date 2026-04-17
*/
@Data
@TableName("ai_group_balance_change_record")
public class AiGroupBalanceChangeRecord implements Serializable {
public class AiGroupBalanceChangeRecord extends BaseEntity {
private static final long serialVersionUID = 1L;
/** $column.columnComment */
@TableId(type = IdType.AUTO)
private Long id;
private String id;
/** 关联订单号 */
/** 关联(充值/退款)订单号 */
@Excel(name = "关联(充值/退款)订单号")
private String relationOrderNo;
/** 部门ID */
@Excel(name = "部门ID")
private Long deptId;
/** 类型0-充值 1-退款 2-下发 3-消费 4-手动修改 */
// GroupBalanceChangeType
private Integer type;
/** 操作类型0-充值、1-退款、2-下发、3-回收、4-手动修改) */
@Excel(name = "操作类型", readConverterExp = "0=-充值、1-退款、2-下发、3-回收、4-手动修改")
private Long type;
/** 变更金额 */
@Excel(name = "变更金额")
private BigDecimal changeAmount;
/** 变更后金额 */
@Excel(name = "变更后金额")
private BigDecimal resultAmount;
private String remark;
private Long createBy;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
}

View File

@ -1,59 +1,63 @@
package com.ruoyi.ai.domain;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.annotation.Excel;
import java.math.BigDecimal;
import lombok.Data;
import com.ruoyi.common.annotation.Excel;
import com.ruoyi.common.core.domain.BaseEntity;
/**
* 视频报表数据 ai_video_report_data
* AI视频生成统计数据作为其他统计报的数据源对象 ai_video_report_data
*
* @author shi
* @date 2026-04-17
*/
@Data
@TableName("ai_video_report_data")
public class AiVideoReportData implements Serializable {
public class AiVideoReportData extends BaseEntity {
private static final long serialVersionUID = 1L;
/** 主键 */
/** $column.columnComment */
@TableId(type = IdType.AUTO)
private Long id;
private String id;
/** 统计日期键varchar */
/** 统计时间到小时yyyyMMddHH */
@Excel(name = "统计时间,到小时('%Y-%m-%d %H')")
private String dateKey;
/** 查询参数统计日期yyyyMMdd */
private String statDate;
/** 部门ID */
@Excel(name = "部门ID")
private Long deptId;
/** 用户ID */
/** 用户ID用户表的ID延用其他表设计 */
@Excel(name = "用户ID用户表的ID延用其他表设计 ")
private Long userId;
/** 积分/分数统计 */
/** 消耗积分,按任务创建时间统计 */
@Excel(name = "消耗积分,按任务创建时间统计")
private BigDecimal score;
/** 订单数 */
/** 实际订单数,只统计已生成成功的任务 */
@Excel(name = "实际订单数,只统计已生成成功的任务")
private Long orderCount;
/** 消耗 tokens */
/** 三方消耗tokens数量按任务创建时间统计 */
@Excel(name = "三方消耗tokens数量按任务创建时间统计")
private Long useTokens;
/** 充值积分 */
/** 实际充值积分(充值-退款) */
@Excel(name = "实际充值积分(充值-退款)")
private BigDecimal rechargeScore;
/** 部门名称(联表字段) */
/** 团队名称(查询结果展示字段) */
@TableField(exist = false)
private String deptName;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
/** 查询日期yyyyMMdd */
@TableField(exist = false)
private String statDate;
}

View File

@ -19,14 +19,6 @@ public interface AiBalanceChangeRecordMapper extends BaseMapper<AiBalanceChangeR
List<AiBalanceChangeRecord> selectAiBalanceChangeRecordList(AiBalanceChangeRecord aiBalanceChangeRecord);
/**
* AI 用户所属部门查询余额流水
*
* @param aiBalanceChangeRecord 查询条件
* @param deptId 部门ID
* @return 余额流水列表
*/
List<AiBalanceChangeRecord> selectAiBalanceChangeRecordListByAiUserDept(
@Param("query") AiBalanceChangeRecord aiBalanceChangeRecord,
List<AiBalanceChangeRecord> selectAiBalanceChangeRecordListByAiUserDept(@Param("q") AiBalanceChangeRecord q,
@Param("deptId") Long deptId);
}

View File

@ -1,18 +1,24 @@
package com.ruoyi.ai.mapper;
import java.util.List;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.ai.domain.AiChargeRefundOrder;
import java.util.List;
/**
* 充值/退款订单 Mapper
* 团队部门充值退款订单Mapper接口
*
* @author shi
* @date 2026-04-17
*/
public interface AiChargeRefundOrderMapper extends BaseMapper<AiChargeRefundOrder> {
/**
* 查询充值/退款订单列表
*
* @param aiChargeRefundOrder 查询条件
* @return 订单列表
* 列表关联团队名称支持按 deptName 模糊查
*/
List<AiChargeRefundOrder> selectAiChargeRefundOrderList(AiChargeRefundOrder aiChargeRefundOrder);
List<AiChargeRefundOrder> selectAiChargeRefundOrderList(AiChargeRefundOrder query);
AiChargeRefundOrder selectAiChargeRefundOrderById(Long id);
int deleteAiChargeRefundOrderByIds(Long[] ids);
}

View File

@ -1,20 +1,15 @@
package com.ruoyi.ai.mapper;
import java.util.List;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.ai.domain.AiDeptArkConfig;
import java.util.List;
/**
* 部门方舟配置 Mapper
* 团队部门对应火山引擎配置Mapper接口
*
* @author shi
* @date 2026-04-17
*/
public interface AiDeptArkConfigMapper extends BaseMapper<AiDeptArkConfig> {
List<AiDeptArkConfig> selectAiDeptArkConfigList(AiDeptArkConfig aiDeptArkConfig);
AiDeptArkConfig selectAiDeptArkConfigById(String id);
int insertAiDeptArkConfig(AiDeptArkConfig aiDeptArkConfig);
int updateAiDeptArkConfig(AiDeptArkConfig aiDeptArkConfig);
int deleteAiDeptArkConfigByIds(String[] ids);
}

View File

@ -1,21 +1,15 @@
package com.ruoyi.ai.mapper;
import java.util.List;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.ai.domain.AiGroupBalanceChangeRecord;
import java.util.List;
/**
* 集团余额变动记录 Mapper
* 团队部门余额变动Mapper接口
*
* @author shi
* @date 2026-04-17
*/
public interface AiGroupBalanceChangeRecordMapper extends BaseMapper<AiGroupBalanceChangeRecord> {
List<AiGroupBalanceChangeRecord> selectAiGroupBalanceChangeRecordList(
AiGroupBalanceChangeRecord aiGroupBalanceChangeRecord);
AiGroupBalanceChangeRecord selectAiGroupBalanceChangeRecordById(String id);
int insertAiGroupBalanceChangeRecord(AiGroupBalanceChangeRecord aiGroupBalanceChangeRecord);
int updateAiGroupBalanceChangeRecord(AiGroupBalanceChangeRecord aiGroupBalanceChangeRecord);
int deleteAiGroupBalanceChangeRecordByIds(String[] ids);
}

View File

@ -1,48 +1,70 @@
package com.ruoyi.ai.mapper;
import java.util.List;
import java.math.BigDecimal;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.ai.domain.AiVideoReportData;
import com.ruoyi.common.core.dto.DeptSummaryDTO;
import com.ruoyi.system.domain.subteam.SubteamVideoMetrics;
import java.math.BigDecimal;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
/**
* 视频报表数据 Mapper
* AI视频生成统计数据作为其他统计报的数据源Mapper接口
*
* @author shi
* @date 2026-04-17
*/
public interface AiVideoReportDataMapper extends BaseMapper<AiVideoReportData> {
@Select("SELECT SUM(order_count) as order_count,SUM(score) as score FROM ai_video_report_data " +
" where dept_id=#{deptId} and date_key>=#{startHour} and date_key<=#{endHour}")
DeptSummaryDTO selectOneDeptSummaryData(Long deptId, String startHour, String endHour);
/**
* 团队每日消耗统计查询按天团队聚合
*
* @param statDate 统计日期yyyyMMdd
* @param deptName 团队名称
* @return 聚合结果
*/
List<AiVideoReportData> selectTeamDailyConsumeList(@Param("statDate") String statDate,
@Param("deptName") String deptName);
List<AiVideoReportData> selectTeamDailyConsumeByDeptId(@Param("statDate") String statDate, @Param("deptId") Long deptId);
/**
* 按团队部门日期聚合团队后台消耗统计
*/
List<AiVideoReportData> selectTeamDailyConsumeByDeptId(@Param("statDate") String statDate,
@Param("deptId") Long deptId);
SubteamVideoMetrics selectDeptVideoMetricsBetween(
@Param("deptId") Long deptId,
/**
* N date_key 日维度汇总消耗积分与成功订单数
*/
SubteamVideoMetrics selectDeptVideoMetricsBetween(@Param("deptId") Long deptId,
@Param("startDay") String startDay,
@Param("endDay") String endDay);
int upsertVideoConsumeIncrement(
@Param("dateKey") String dateKey,
/**
* date_key, dept_id, user_id聚合累加视频消耗统计
*
* @param dateKey 小时KeyyyyyMMddHH
* @param deptId 部门ID
* @param userId 用户ID
* @param score 消耗积分增量
* @param orderCount 订单数增量
* @param useTokens 三方tokens增量
* @return 影响行数
*/
int upsertVideoConsumeIncrement(@Param("dateKey") String dateKey,
@Param("deptId") Long deptId,
@Param("userId") Long userId,
@Param("score") BigDecimal score,
@Param("orderCount") Long orderCount,
@Param("useTokens") Long useTokens);
List<AiVideoReportData> selectTeamDailyConsumeList(
@Param("statDate") String statDate,
@Param("deptName") String deptName);
List<AiVideoReportData> selectAiVideoReportDataList(AiVideoReportData aiVideoReportData);
AiVideoReportData selectAiVideoReportDataById(String id);
int insertAiVideoReportData(AiVideoReportData aiVideoReportData);
int updateAiVideoReportData(AiVideoReportData aiVideoReportData);
int deleteAiVideoReportDataByIds(String[] ids);
/**
* date_key, dept_id, user_id=0聚合累加充值积分统计
*
* @param dateKey 小时KeyyyyyMMddHH
* @param deptId 部门ID
* @param rechargeScore 充值积分增量
* @return 影响行数
*/
int upsertRechargeScoreIncrement(@Param("dateKey") String dateKey,
@Param("deptId") Long deptId,
@Param("rechargeScore") BigDecimal rechargeScore);
}

View File

@ -1,28 +1,71 @@
package com.ruoyi.ai.service;
import com.ruoyi.ai.domain.AiChargeRefundOrder;
import java.util.List;
import com.ruoyi.ai.domain.AiChargeRefundOrder;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
/**
* 充值/退款订单 Service
* 团队部门充值退款订单Service接口
*
* @author shi
* @date 2026-04-17
*/
public interface IAiChargeRefundOrderService {
AiChargeRefundOrder selectById(Long id);
int insert(AiChargeRefundOrder entity);
int updateById(AiChargeRefundOrder entity);
int deleteById(Long id);
List<AiChargeRefundOrder> selectAiChargeRefundOrderList(AiChargeRefundOrder aiChargeRefundOrder);
/**
* 查询团队部门充值退款订单
*
* @param id 团队部门充值退款订单主键
* @return 团队部门充值退款订单
*/
AiChargeRefundOrder selectAiChargeRefundOrderById(Long id);
/**
* 查询团队部门充值退款订单列表
*
* @param aiChargeRefundOrder 团队部门充值退款订单
* @return 团队部门充值退款订单集合
*/
List<AiChargeRefundOrder> selectAiChargeRefundOrderList(AiChargeRefundOrder aiChargeRefundOrder);
/**
* 分页查询团队部门充值退款订单列表
*
* @param aiChargeRefundOrder 团队部门充值退款订单
* @return 团队部门充值退款订单集合
*/
IPage<AiChargeRefundOrder> selectAiChargeRefundOrderPage(Page page, AiChargeRefundOrder aiChargeRefundOrder);
/**
* 新增团队部门充值退款订单
*
* @param aiChargeRefundOrder 团队部门充值退款订单
* @return 结果
*/
int insertAiChargeRefundOrder(AiChargeRefundOrder aiChargeRefundOrder);
/**
* 修改团队部门充值退款订单
*
* @param aiChargeRefundOrder 团队部门充值退款订单
* @return 结果
*/
int updateAiChargeRefundOrder(AiChargeRefundOrder aiChargeRefundOrder);
/**
* 批量删除团队部门充值退款订单
*
* @param ids 需要删除的团队部门充值退款订单主键集合
* @return 结果
*/
int deleteAiChargeRefundOrderByIds(Long[] ids);
/**
* 删除团队部门充值退款订单信息
*
* @param id 团队部门充值退款订单主键
* @return 结果
*/
int deleteAiChargeRefundOrderById(Long id);
}

View File

@ -1,28 +1,71 @@
package com.ruoyi.ai.service;
import com.ruoyi.ai.domain.AiDeptArkConfig;
import java.util.List;
import com.ruoyi.ai.domain.AiDeptArkConfig;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
/**
* 部门方舟配置 Service
* 团队部门对应火山引擎配置Service接口
*
* @author shi
* @date 2026-04-17
*/
public interface IAiDeptArkConfigService {
AiDeptArkConfig selectById(Long id);
int insert(AiDeptArkConfig entity);
int updateById(AiDeptArkConfig entity);
int deleteById(Long id);
List<AiDeptArkConfig> selectAiDeptArkConfigList(AiDeptArkConfig aiDeptArkConfig);
/**
* 查询团队部门对应火山引擎配置
*
* @param id 团队部门对应火山引擎配置主键
* @return 团队部门对应火山引擎配置
*/
AiDeptArkConfig selectAiDeptArkConfigById(String id);
/**
* 查询团队部门对应火山引擎配置列表
*
* @param aiDeptArkConfig 团队部门对应火山引擎配置
* @return 团队部门对应火山引擎配置集合
*/
List<AiDeptArkConfig> selectAiDeptArkConfigList(AiDeptArkConfig aiDeptArkConfig);
/**
* 分页查询团队部门对应火山引擎配置列表
*
* @param aiDeptArkConfig 团队部门对应火山引擎配置
* @return 团队部门对应火山引擎配置集合
*/
IPage<AiDeptArkConfig> selectAiDeptArkConfigPage(Page page, AiDeptArkConfig aiDeptArkConfig);
/**
* 新增团队部门对应火山引擎配置
*
* @param aiDeptArkConfig 团队部门对应火山引擎配置
* @return 结果
*/
int insertAiDeptArkConfig(AiDeptArkConfig aiDeptArkConfig);
/**
* 修改团队部门对应火山引擎配置
*
* @param aiDeptArkConfig 团队部门对应火山引擎配置
* @return 结果
*/
int updateAiDeptArkConfig(AiDeptArkConfig aiDeptArkConfig);
/**
* 批量删除团队部门对应火山引擎配置
*
* @param ids 需要删除的团队部门对应火山引擎配置主键集合
* @return 结果
*/
int deleteAiDeptArkConfigByIds(String[] ids);
/**
* 删除团队部门对应火山引擎配置信息
*
* @param id 团队部门对应火山引擎配置主键
* @return 结果
*/
int deleteAiDeptArkConfigById(String id);
}

View File

@ -1,29 +1,71 @@
package com.ruoyi.ai.service;
import com.ruoyi.ai.domain.AiGroupBalanceChangeRecord;
import java.util.List;
import com.ruoyi.ai.domain.AiGroupBalanceChangeRecord;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
/**
* 集团余额变动记录 Service
* 团队部门余额变动Service接口
*
* @author shi
* @date 2026-04-17
*/
public interface IAiGroupBalanceChangeRecordService {
AiGroupBalanceChangeRecord selectById(Long id);
int insert(AiGroupBalanceChangeRecord entity);
int updateById(AiGroupBalanceChangeRecord entity);
int deleteById(Long id);
List<AiGroupBalanceChangeRecord> selectAiGroupBalanceChangeRecordList(
AiGroupBalanceChangeRecord aiGroupBalanceChangeRecord);
/**
* 查询团队部门余额变动
*
* @param id 团队部门余额变动主键
* @return 团队部门余额变动
*/
AiGroupBalanceChangeRecord selectAiGroupBalanceChangeRecordById(String id);
/**
* 查询团队部门余额变动列表
*
* @param aiGroupBalanceChangeRecord 团队部门余额变动
* @return 团队部门余额变动集合
*/
List<AiGroupBalanceChangeRecord> selectAiGroupBalanceChangeRecordList(AiGroupBalanceChangeRecord aiGroupBalanceChangeRecord);
/**
* 分页查询团队部门余额变动列表
*
* @param aiGroupBalanceChangeRecord 团队部门余额变动
* @return 团队部门余额变动集合
*/
IPage<AiGroupBalanceChangeRecord> selectAiGroupBalanceChangeRecordPage(Page page, AiGroupBalanceChangeRecord aiGroupBalanceChangeRecord);
/**
* 新增团队部门余额变动
*
* @param aiGroupBalanceChangeRecord 团队部门余额变动
* @return 结果
*/
int insertAiGroupBalanceChangeRecord(AiGroupBalanceChangeRecord aiGroupBalanceChangeRecord);
/**
* 修改团队部门余额变动
*
* @param aiGroupBalanceChangeRecord 团队部门余额变动
* @return 结果
*/
int updateAiGroupBalanceChangeRecord(AiGroupBalanceChangeRecord aiGroupBalanceChangeRecord);
/**
* 批量删除团队部门余额变动
*
* @param ids 需要删除的团队部门余额变动主键集合
* @return 结果
*/
int deleteAiGroupBalanceChangeRecordByIds(String[] ids);
/**
* 删除团队部门余额变动信息
*
* @param id 团队部门余额变动主键
* @return 结果
*/
int deleteAiGroupBalanceChangeRecordById(String id);
}

View File

@ -1,51 +1,107 @@
package com.ruoyi.ai.service;
import com.ruoyi.ai.domain.AiVideoReportData;
import com.ruoyi.common.core.dto.DeptSummaryDTO;
import java.math.BigDecimal;
import java.util.List;
import java.math.BigDecimal;
import java.util.Date;
import com.ruoyi.ai.domain.AiVideoReportData;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
/**
* 视频报表数据 Service
* AI视频生成统计数据作为其他统计报的数据源Service接口
*
* @author shi
* @date 2026-04-17
*/
public interface IAiVideoReportDataService {
AiVideoReportData selectById(Long id);
int insert(AiVideoReportData entity);
DeptSummaryDTO getSevenDayDeptSummaryData(Long deptId);
/**
* 按部门查询团队每日消耗
* 查询AI视频生成统计数据作为其他统计报的数据源
*
* @param statDate 统计日期yyyyMMdd
* @param deptId 部门ID
* @return 每日消耗列表
* @param id AI视频生成统计数据作为其他统计报的数据源主键
* @return AI视频生成统计数据作为其他统计报的数据源
*/
AiVideoReportData selectAiVideoReportDataById(String id);
/**
* 查询AI视频生成统计数据作为其他统计报的数据源列表
*
* @param aiVideoReportData AI视频生成统计数据作为其他统计报的数据源
* @return AI视频生成统计数据作为其他统计报的数据源集合
*/
List<AiVideoReportData> selectAiVideoReportDataList(AiVideoReportData aiVideoReportData);
/**
* 分页查询AI视频生成统计数据作为其他统计报的数据源列表
*
* @param aiVideoReportData AI视频生成统计数据作为其他统计报的数据源
* @return AI视频生成统计数据作为其他统计报的数据源集合
*/
IPage<AiVideoReportData> selectAiVideoReportDataPage(Page page, AiVideoReportData aiVideoReportData);
/**
* 新增AI视频生成统计数据作为其他统计报的数据源
*
* @param aiVideoReportData AI视频生成统计数据作为其他统计报的数据源
* @return 结果
*/
int insertAiVideoReportData(AiVideoReportData aiVideoReportData);
/**
* 修改AI视频生成统计数据作为其他统计报的数据源
*
* @param aiVideoReportData AI视频生成统计数据作为其他统计报的数据源
* @return 结果
*/
int updateAiVideoReportData(AiVideoReportData aiVideoReportData);
/**
* 批量删除AI视频生成统计数据作为其他统计报的数据源
*
* @param ids 需要删除的AI视频生成统计数据作为其他统计报的数据源主键集合
* @return 结果
*/
int deleteAiVideoReportDataByIds(String[] ids);
/**
* 删除AI视频生成统计数据作为其他统计报的数据源信息
*
* @param id AI视频生成统计数据作为其他统计报的数据源主键
* @return 结果
*/
int deleteAiVideoReportDataById(String id);
/**
* 团队每日消耗统计查询按天团队聚合
*
* @param statDate 统计日期yyyyMMdd必填
* @param deptName 团队名称必填模糊匹配
* @return 聚合后的统计数据
*/
List<AiVideoReportData> selectTeamDailyConsumeList(String statDate, String deptName);
/**
* 团队每日消耗按部门 ID团队后台
*/
List<AiVideoReportData> selectTeamDailyConsumeByDeptId(String statDate, Long deptId);
/**
* 同步视频消耗增量
* 按视频订单成功结果回写统计来源表按小时部门账号聚合累加
*
* @param createTime 订单创建时间
* @param createTime 任务创建时间
* @param deptId 部门ID
* @param userId 用户ID
* @param score 消耗积分
* @param useTokens 消耗token
* @param userId 账号ID
* @param score 消耗积分增量
* @param useTokens 三方tokens增量
*/
void syncVideoConsumeIncrement(Date createTime, Long deptId, Long userId, BigDecimal score, Long useTokens);
List<AiVideoReportData> selectTeamDailyConsumeList(String statDate, String deptName);
List<AiVideoReportData> selectAiVideoReportDataList(AiVideoReportData aiVideoReportData);
AiVideoReportData selectAiVideoReportDataById(String id);
int insertAiVideoReportData(AiVideoReportData aiVideoReportData);
int updateAiVideoReportData(AiVideoReportData aiVideoReportData);
int deleteAiVideoReportDataByIds(String[] ids);
/**
* 按充值/退款成功结果回写统计来源表按小时部门聚合累加
*
* @param createTime 订单创建时间
* @param deptId 部门ID
* @param rechargeScore 实际充值积分增量充值为正退款为负
*/
void syncRechargeScoreIncrement(Date createTime, Long deptId, BigDecimal rechargeScore);
}

View File

@ -1,15 +1,30 @@
package com.ruoyi.ai.service.impl;
import java.util.List;
import java.math.BigDecimal;
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.extension.plugins.pagination.Page;
import com.ruoyi.common.enums.ChargeRefundOrderStatusType;
import com.ruoyi.common.enums.ChargeRefundOrderType;
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.common.utils.uuid.IdUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.ai.domain.AiChargeRefundOrder;
import com.ruoyi.ai.mapper.AiChargeRefundOrderMapper;
import com.ruoyi.ai.domain.AiChargeRefundOrder;
import com.ruoyi.ai.service.IAiVideoReportDataService;
import com.ruoyi.ai.service.IAiChargeRefundOrderService;
import java.util.List;
/**
* 充值/退款订单 Service 实现
* 团队部门充值退款订单Service业务层处理
*
* @author shi
* @date 2026-04-17
*/
@Service
public class AiChargeRefundOrderServiceImpl implements IAiChargeRefundOrderService {
@ -17,55 +32,151 @@ public class AiChargeRefundOrderServiceImpl implements IAiChargeRefundOrderServi
@Autowired
private AiChargeRefundOrderMapper aiChargeRefundOrderMapper;
@Autowired
private IAiVideoReportDataService aiVideoReportDataService;
/**
* 查询团队部门充值退款订单
*
* @param id 团队部门充值退款订单主键
* @return 团队部门充值退款订单
*/
@Override
public AiChargeRefundOrder selectById(Long id) {
return aiChargeRefundOrderMapper.selectById(id);
}
@Override
public int insert(AiChargeRefundOrder entity) {
return aiChargeRefundOrderMapper.insert(entity);
}
@Override
public int updateById(AiChargeRefundOrder entity) {
return aiChargeRefundOrderMapper.updateById(entity);
}
@Override
public int deleteById(Long id) {
return aiChargeRefundOrderMapper.deleteById(id);
public AiChargeRefundOrder selectAiChargeRefundOrderById(Long id) {
return aiChargeRefundOrderMapper.selectAiChargeRefundOrderById(id);
}
/**
* 查询团队部门充值退款订单列表
*
* @param aiChargeRefundOrder 团队部门充值退款订单
* @return 团队部门充值退款订单
*/
@Override
public List<AiChargeRefundOrder> selectAiChargeRefundOrderList(AiChargeRefundOrder aiChargeRefundOrder) {
return aiChargeRefundOrderMapper.selectAiChargeRefundOrderList(aiChargeRefundOrder);
}
/**
* 分页查询团队部门充值退款订单列表
*
* @param aiChargeRefundOrder 团队部门充值退款订单
* @return 团队部门充值退款订单
*/
@Override
public AiChargeRefundOrder selectAiChargeRefundOrderById(Long id) {
return aiChargeRefundOrderMapper.selectById(id);
public IPage<AiChargeRefundOrder> selectAiChargeRefundOrderPage(Page page, AiChargeRefundOrder aiChargeRefundOrder) {
if (aiChargeRefundOrder != null) {
aiChargeRefundOrder.setDeptName(null);
}
LambdaQueryWrapper<AiChargeRefundOrder> query = Wrappers.lambdaQuery(aiChargeRefundOrder);
query.eq(AiChargeRefundOrder::getDelFlag, "0");
return aiChargeRefundOrderMapper.selectPage(page, query);
}
/**
* 新增团队部门充值退款订单
*
* @param aiChargeRefundOrder 团队部门充值退款订单
* @return 结果
*/
@Override
public int insertAiChargeRefundOrder(AiChargeRefundOrder aiChargeRefundOrder) {
return aiChargeRefundOrderMapper.insert(aiChargeRefundOrder);
validateChargeAmount(aiChargeRefundOrder);
if (StringUtils.isEmpty(aiChargeRefundOrder.getOrderNum())) {
aiChargeRefundOrder.setOrderNum("CR" + IdUtils.fastSimpleUUID());
}
if (aiChargeRefundOrder.getStatus() == null) {
aiChargeRefundOrder.setStatus(ChargeRefundOrderStatusType.SUCCESS.getCode());
}
aiChargeRefundOrder.setDelFlag("0");
aiChargeRefundOrder.setCreateBy(SecurityUtils.getUsername());
aiChargeRefundOrder.setCreateTime(DateUtils.getNowDate());
int rows = aiChargeRefundOrderMapper.insert(aiChargeRefundOrder);
syncRechargeReportData(aiChargeRefundOrder);
return rows;
}
/**
* 修改团队部门充值退款订单
*
* @param aiChargeRefundOrder 团队部门充值退款订单
* @return 结果
*/
@Override
public int updateAiChargeRefundOrder(AiChargeRefundOrder aiChargeRefundOrder) {
return aiChargeRefundOrderMapper.updateById(aiChargeRefundOrder);
validateChargeAmount(aiChargeRefundOrder);
aiChargeRefundOrder.setUpdateTime(DateUtils.getNowDate());
int rows = aiChargeRefundOrderMapper.updateById(aiChargeRefundOrder);
if (rows > 0) {
AiChargeRefundOrder fresh = aiChargeRefundOrderMapper.selectById(aiChargeRefundOrder.getId());
syncRechargeReportData(fresh);
}
return rows;
}
/**
* 批量删除团队部门充值退款订单
*
* @param ids 需要删除的团队部门充值退款订单主键
* @return 结果
*/
@Override
public int deleteAiChargeRefundOrderByIds(Long[] ids) {
int rows = 0;
if (ids == null) {
return rows;
public int deleteAiChargeRefundOrderByIds(Long[] ids)
{
return aiChargeRefundOrderMapper.deleteAiChargeRefundOrderByIds(ids);
}
/**
* 删除团队部门充值退款订单信息
*
* @param id 团队部门充值退款订单主键
* @return 结果
*/
@Override
public int deleteAiChargeRefundOrderById(Long id)
{
return aiChargeRefundOrderMapper.deleteById(id);
}
/**
* 充值/退款单完成后订单创建时间同步到团队统计来源表
*
* @param order 充值退款订单
*/
private void syncRechargeReportData(AiChargeRefundOrder order) {
if (order == null || order.getCreateTime() == null || order.getDeptId() == null) {
return;
}
if (order.getStatus() == null || order.getStatus() != ChargeRefundOrderStatusType.SUCCESS.getCode()) {
return;
}
if (order.getOrderType() == null || order.getAmount() == null) {
return;
}
BigDecimal rechargeScore;
int type = order.getOrderType().intValue();
if (type == ChargeRefundOrderType.REFUND.getCode()) {
rechargeScore = order.getAmount().negate();
} else if (type == ChargeRefundOrderType.MANUAL.getCode()) {
rechargeScore = order.getAmount();
} else {
rechargeScore = order.getAmount();
}
aiVideoReportDataService.syncRechargeScoreIncrement(order.getCreateTime(), order.getDeptId(), rechargeScore);
}
/**
* 充值退款积分须为非负数手动修改允许正负
*/
private void validateChargeAmount(AiChargeRefundOrder o) {
if (o.getOrderType() == null || o.getAmount() == null) {
return;
}
int t = o.getOrderType().intValue();
if (t == ChargeRefundOrderType.CHARGE.getCode() || t == ChargeRefundOrderType.REFUND.getCode()) {
if (o.getAmount().compareTo(BigDecimal.ZERO) < 0) {
throw new ServiceException("充值、退款类型的积分须填写非负数");
}
for (Long id : ids) {
rows += aiChargeRefundOrderMapper.deleteById(id);
}
return rows;
}
}

View File

@ -1,15 +1,23 @@
package com.ruoyi.ai.service.impl;
import java.util.List;
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.extension.plugins.pagination.Page;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.ai.domain.AiDeptArkConfig;
import com.ruoyi.ai.mapper.AiDeptArkConfigMapper;
import com.ruoyi.ai.domain.AiDeptArkConfig;
import com.ruoyi.ai.service.IAiDeptArkConfigService;
import java.util.List;
/**
* 部门方舟配置 Service 实现
* 团队部门对应火山引擎配置Service业务层处理
*
* @author shi
* @date 2026-04-17
*/
@Service
public class AiDeptArkConfigServiceImpl implements IAiDeptArkConfigService {
@ -17,48 +25,89 @@ public class AiDeptArkConfigServiceImpl implements IAiDeptArkConfigService {
@Autowired
private AiDeptArkConfigMapper aiDeptArkConfigMapper;
/**
* 查询团队部门对应火山引擎配置
*
* @param id 团队部门对应火山引擎配置主键
* @return 团队部门对应火山引擎配置
*/
@Override
public AiDeptArkConfig selectById(Long id) {
public AiDeptArkConfig selectAiDeptArkConfigById(String id) {
return aiDeptArkConfigMapper.selectById(id);
}
@Override
public int insert(AiDeptArkConfig entity) {
return aiDeptArkConfigMapper.insert(entity);
}
@Override
public int updateById(AiDeptArkConfig entity) {
return aiDeptArkConfigMapper.updateById(entity);
}
@Override
public int deleteById(Long id) {
return aiDeptArkConfigMapper.deleteById(id);
}
/**
* 查询团队部门对应火山引擎配置列表
*
* @param aiDeptArkConfig 团队部门对应火山引擎配置
* @return 团队部门对应火山引擎配置
*/
@Override
public List<AiDeptArkConfig> selectAiDeptArkConfigList(AiDeptArkConfig aiDeptArkConfig) {
return aiDeptArkConfigMapper.selectAiDeptArkConfigList(aiDeptArkConfig);
LambdaQueryWrapper<AiDeptArkConfig> query = Wrappers.lambdaQuery(aiDeptArkConfig);
query.orderByDesc(AiDeptArkConfig::getId);
return aiDeptArkConfigMapper.selectList(query);
}
/**
* 分页查询团队部门对应火山引擎配置列表
*
* @param aiDeptArkConfig 团队部门对应火山引擎配置
* @return 团队部门对应火山引擎配置
*/
@Override
public AiDeptArkConfig selectAiDeptArkConfigById(String id) {
return aiDeptArkConfigMapper.selectAiDeptArkConfigById(id);
public IPage<AiDeptArkConfig> selectAiDeptArkConfigPage(Page page, AiDeptArkConfig aiDeptArkConfig) {
LambdaQueryWrapper<AiDeptArkConfig> query = Wrappers.lambdaQuery(aiDeptArkConfig);
return aiDeptArkConfigMapper.selectPage(page, query);
}
/**
* 新增团队部门对应火山引擎配置
*
* @param aiDeptArkConfig 团队部门对应火山引擎配置
* @return 结果
*/
@Override
public int insertAiDeptArkConfig(AiDeptArkConfig aiDeptArkConfig) {
return aiDeptArkConfigMapper.insertAiDeptArkConfig(aiDeptArkConfig);
aiDeptArkConfig.setCreateBy(SecurityUtils.getUsername());
aiDeptArkConfig.setCreateTime(DateUtils.getNowDate());
return aiDeptArkConfigMapper.insert(aiDeptArkConfig);
}
/**
* 修改团队部门对应火山引擎配置
*
* @param aiDeptArkConfig 团队部门对应火山引擎配置
* @return 结果
*/
@Override
public int updateAiDeptArkConfig(AiDeptArkConfig aiDeptArkConfig) {
return aiDeptArkConfigMapper.updateAiDeptArkConfig(aiDeptArkConfig);
aiDeptArkConfig.setUpdateBy(SecurityUtils.getUsername());
aiDeptArkConfig.setUpdateTime(DateUtils.getNowDate());
return aiDeptArkConfigMapper.updateById(aiDeptArkConfig);
}
/**
* 批量删除团队部门对应火山引擎配置
*
* @param ids 需要删除的团队部门对应火山引擎配置主键
* @return 结果
*/
@Override
public int deleteAiDeptArkConfigByIds(String[] ids) {
return aiDeptArkConfigMapper.deleteAiDeptArkConfigByIds(ids);
public int deleteAiDeptArkConfigByIds(String[] ids)
{
return aiDeptArkConfigMapper.deleteBatchIds(java.util.Arrays.asList(ids));
}
/**
* 删除团队部门对应火山引擎配置信息
*
* @param id 团队部门对应火山引擎配置主键
* @return 结果
*/
@Override
public int deleteAiDeptArkConfigById(String id)
{
return aiDeptArkConfigMapper.deleteById(id);
}
}

View File

@ -1,15 +1,22 @@
package com.ruoyi.ai.service.impl;
import java.util.List;
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.extension.plugins.pagination.Page;
import com.ruoyi.common.utils.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.ai.domain.AiGroupBalanceChangeRecord;
import com.ruoyi.ai.mapper.AiGroupBalanceChangeRecordMapper;
import com.ruoyi.ai.domain.AiGroupBalanceChangeRecord;
import com.ruoyi.ai.service.IAiGroupBalanceChangeRecordService;
import java.util.List;
/**
* 集团余额变动记录 Service 实现
* 团队部门余额变动Service业务层处理
*
* @author shi
* @date 2026-04-17
*/
@Service
public class AiGroupBalanceChangeRecordServiceImpl implements IAiGroupBalanceChangeRecordService {
@ -17,49 +24,87 @@ public class AiGroupBalanceChangeRecordServiceImpl implements IAiGroupBalanceCha
@Autowired
private AiGroupBalanceChangeRecordMapper aiGroupBalanceChangeRecordMapper;
/**
* 查询团队部门余额变动
*
* @param id 团队部门余额变动主键
* @return 团队部门余额变动
*/
@Override
public AiGroupBalanceChangeRecord selectById(Long id) {
public AiGroupBalanceChangeRecord selectAiGroupBalanceChangeRecordById(String id) {
return aiGroupBalanceChangeRecordMapper.selectById(id);
}
/**
* 查询团队部门余额变动列表
*
* @param aiGroupBalanceChangeRecord 团队部门余额变动
* @return 团队部门余额变动
*/
@Override
public int insert(AiGroupBalanceChangeRecord entity) {
return aiGroupBalanceChangeRecordMapper.insert(entity);
public List<AiGroupBalanceChangeRecord> selectAiGroupBalanceChangeRecordList(AiGroupBalanceChangeRecord aiGroupBalanceChangeRecord) {
LambdaQueryWrapper<AiGroupBalanceChangeRecord> query = Wrappers.lambdaQuery(aiGroupBalanceChangeRecord);
query.orderByDesc(AiGroupBalanceChangeRecord::getId);
return aiGroupBalanceChangeRecordMapper.selectList(query);
}
/**
* 分页查询团队部门余额变动列表
*
* @param aiGroupBalanceChangeRecord 团队部门余额变动
* @return 团队部门余额变动
*/
@Override
public int updateById(AiGroupBalanceChangeRecord entity) {
return aiGroupBalanceChangeRecordMapper.updateById(entity);
}
@Override
public int deleteById(Long id) {
return aiGroupBalanceChangeRecordMapper.deleteById(id);
}
@Override
public List<AiGroupBalanceChangeRecord> selectAiGroupBalanceChangeRecordList(
AiGroupBalanceChangeRecord aiGroupBalanceChangeRecord) {
return aiGroupBalanceChangeRecordMapper.selectAiGroupBalanceChangeRecordList(aiGroupBalanceChangeRecord);
}
@Override
public AiGroupBalanceChangeRecord selectAiGroupBalanceChangeRecordById(String id) {
return aiGroupBalanceChangeRecordMapper.selectAiGroupBalanceChangeRecordById(id);
public IPage<AiGroupBalanceChangeRecord> selectAiGroupBalanceChangeRecordPage(Page page, AiGroupBalanceChangeRecord aiGroupBalanceChangeRecord) {
LambdaQueryWrapper<AiGroupBalanceChangeRecord> query = Wrappers.lambdaQuery(aiGroupBalanceChangeRecord);
return aiGroupBalanceChangeRecordMapper.selectPage(page, query);
}
/**
* 新增团队部门余额变动
*
* @param aiGroupBalanceChangeRecord 团队部门余额变动
* @return 结果
*/
@Override
public int insertAiGroupBalanceChangeRecord(AiGroupBalanceChangeRecord aiGroupBalanceChangeRecord) {
return aiGroupBalanceChangeRecordMapper.insertAiGroupBalanceChangeRecord(aiGroupBalanceChangeRecord);
aiGroupBalanceChangeRecord.setCreateTime(DateUtils.getNowDate());
return aiGroupBalanceChangeRecordMapper.insert(aiGroupBalanceChangeRecord);
}
/**
* 修改团队部门余额变动
*
* @param aiGroupBalanceChangeRecord 团队部门余额变动
* @return 结果
*/
@Override
public int updateAiGroupBalanceChangeRecord(AiGroupBalanceChangeRecord aiGroupBalanceChangeRecord) {
return aiGroupBalanceChangeRecordMapper.updateAiGroupBalanceChangeRecord(aiGroupBalanceChangeRecord);
aiGroupBalanceChangeRecord.setUpdateTime(DateUtils.getNowDate());
return aiGroupBalanceChangeRecordMapper.updateById(aiGroupBalanceChangeRecord);
}
/**
* 批量删除团队部门余额变动
*
* @param ids 需要删除的团队部门余额变动主键
* @return 结果
*/
@Override
public int deleteAiGroupBalanceChangeRecordByIds(String[] ids) {
return aiGroupBalanceChangeRecordMapper.deleteAiGroupBalanceChangeRecordByIds(ids);
public int deleteAiGroupBalanceChangeRecordByIds(String[] ids)
{
return aiGroupBalanceChangeRecordMapper.deleteBatchIds(java.util.Arrays.asList(ids));
}
/**
* 删除团队部门余额变动信息
*
* @param id 团队部门余额变动主键
* @return 结果
*/
@Override
public int deleteAiGroupBalanceChangeRecordById(String id)
{
return aiGroupBalanceChangeRecordMapper.deleteById(id);
}
}

View File

@ -1,114 +1,141 @@
package com.ruoyi.ai.service.impl;
import com.ruoyi.ai.domain.AiVideoReportData;
import com.ruoyi.ai.mapper.AiVideoReportDataMapper;
import com.ruoyi.ai.service.IAiVideoReportDataService;
import com.ruoyi.common.constant.RedisKey;
import com.ruoyi.common.core.dto.DeptSummaryDTO;
import com.ruoyi.common.utils.DateUtils;
import java.math.BigDecimal;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
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.extension.plugins.pagination.Page;
import com.ruoyi.common.utils.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.ai.mapper.AiVideoReportDataMapper;
import com.ruoyi.ai.domain.AiVideoReportData;
import com.ruoyi.ai.service.IAiVideoReportDataService;
/**
* 视频报表数据 Service 实现
* AI视频生成统计数据作为其他统计报的数据源Service业务层处理
*
* @author shi
* @date 2026-04-17
*/
@Service
public class AiVideoReportDataServiceImpl implements IAiVideoReportDataService {
/** 与表字段 date_key 一致yyyy-MM-dd HH线程安全 */
private static final DateTimeFormatter DATE_KEY_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH");
@Autowired
private AiVideoReportDataMapper videoReportDataMapper;
private AiVideoReportDataMapper aiVideoReportDataMapper;
/**
* 查询AI视频生成统计数据作为其他统计报的数据源
*
* @param id AI视频生成统计数据作为其他统计报的数据源主键
* @return AI视频生成统计数据作为其他统计报的数据源
*/
@Override
public AiVideoReportData selectById(Long id) {
return videoReportDataMapper.selectById(id);
}
@Override
public int insert(AiVideoReportData entity) {
return videoReportDataMapper.insert(entity);
public AiVideoReportData selectAiVideoReportDataById(String id) {
return aiVideoReportDataMapper.selectById(id);
}
/**
* 部门近七日汇总数据
* 查询AI视频生成统计数据作为其他统计报的数据源列表
*
* @param aiVideoReportData AI视频生成统计数据作为其他统计报的数据源
* @return AI视频生成统计数据作为其他统计报的数据源
*/
@Override
@Cacheable(cacheNames = RedisKey.CACHE_DEPT_SUMMARY, key = "#deptId")
public DeptSummaryDTO getSevenDayDeptSummaryData(Long deptId) {
Date endTime = new Date();
// 获取今天的0点再减去7天
Date todayZero = DateUtils.truncate(endTime, Calendar.DAY_OF_MONTH);
Date startTime = DateUtils.addDays(todayZero, -7);
String startHour = formatDateKey(startTime);
String endHour = formatDateKey(endTime);
return videoReportDataMapper.selectOneDeptSummaryData(deptId, startHour, endHour);
public List<AiVideoReportData> selectAiVideoReportDataList(AiVideoReportData aiVideoReportData) {
LambdaQueryWrapper<AiVideoReportData> query = Wrappers.lambdaQuery(aiVideoReportData);
query.orderByDesc(AiVideoReportData::getId);
return aiVideoReportDataMapper.selectList(query);
}
/**
* 分页查询AI视频生成统计数据作为其他统计报的数据源列表
*
* @param aiVideoReportData AI视频生成统计数据作为其他统计报的数据源
* @return AI视频生成统计数据作为其他统计报的数据源
*/
@Override
public List<AiVideoReportData> selectTeamDailyConsumeByDeptId(String statDate, Long deptId) {
return videoReportDataMapper.selectTeamDailyConsumeByDeptId(statDate, deptId);
public IPage<AiVideoReportData> selectAiVideoReportDataPage(Page page, AiVideoReportData aiVideoReportData) {
LambdaQueryWrapper<AiVideoReportData> query = Wrappers.lambdaQuery(aiVideoReportData);
return aiVideoReportDataMapper.selectPage(page, query);
}
/**
* 新增AI视频生成统计数据作为其他统计报的数据源
*
* @param aiVideoReportData AI视频生成统计数据作为其他统计报的数据源
* @return 结果
*/
@Override
public void syncVideoConsumeIncrement(Date createTime, Long deptId, Long userId, BigDecimal score, Long useTokens) {
if (createTime == null || deptId == null || userId == null) {
return;
public int insertAiVideoReportData(AiVideoReportData aiVideoReportData) {
aiVideoReportData.setCreateTime(DateUtils.getNowDate());
return aiVideoReportDataMapper.insert(aiVideoReportData);
}
BigDecimal scoreSafe = score != null ? score : BigDecimal.ZERO;
Long useTokensSafe = useTokens != null ? useTokens : 0L;
videoReportDataMapper.upsertVideoConsumeIncrement(
formatDateKey(createTime),
deptId,
userId,
scoreSafe,
1L,
useTokensSafe);
/**
* 修改AI视频生成统计数据作为其他统计报的数据源
*
* @param aiVideoReportData AI视频生成统计数据作为其他统计报的数据源
* @return 结果
*/
@Override
public int updateAiVideoReportData(AiVideoReportData aiVideoReportData) {
aiVideoReportData.setUpdateTime(DateUtils.getNowDate());
return aiVideoReportDataMapper.updateById(aiVideoReportData);
}
/**
* 批量删除AI视频生成统计数据作为其他统计报的数据源
*
* @param ids 需要删除的AI视频生成统计数据作为其他统计报的数据源主键
* @return 结果
*/
@Override
public int deleteAiVideoReportDataByIds(String[] ids)
{
return aiVideoReportDataMapper.deleteBatchIds(java.util.Arrays.asList(ids));
}
/**
* 删除AI视频生成统计数据作为其他统计报的数据源信息
*
* @param id AI视频生成统计数据作为其他统计报的数据源主键
* @return 结果
*/
@Override
public int deleteAiVideoReportDataById(String id)
{
return aiVideoReportDataMapper.deleteById(id);
}
@Override
public List<AiVideoReportData> selectTeamDailyConsumeList(String statDate, String deptName) {
return videoReportDataMapper.selectTeamDailyConsumeList(statDate, deptName);
return aiVideoReportDataMapper.selectTeamDailyConsumeList(statDate, deptName);
}
@Override
public List<AiVideoReportData> selectAiVideoReportDataList(AiVideoReportData aiVideoReportData) {
return videoReportDataMapper.selectAiVideoReportDataList(aiVideoReportData);
public List<AiVideoReportData> selectTeamDailyConsumeByDeptId(String statDate, Long deptId) {
return aiVideoReportDataMapper.selectTeamDailyConsumeByDeptId(statDate, deptId);
}
@Override
public AiVideoReportData selectAiVideoReportDataById(String id) {
return videoReportDataMapper.selectAiVideoReportDataById(id);
public void syncVideoConsumeIncrement(Date createTime, Long deptId, Long userId, BigDecimal score, Long useTokens) {
if (createTime == null || deptId == null || userId == null || score == null || useTokens == null) {
return;
}
String dateKey = new SimpleDateFormat("yyyyMMddHH").format(createTime);
aiVideoReportDataMapper.upsertVideoConsumeIncrement(dateKey, deptId, userId, score, 1L, useTokens);
}
@Override
public int insertAiVideoReportData(AiVideoReportData aiVideoReportData) {
return videoReportDataMapper.insertAiVideoReportData(aiVideoReportData);
public void syncRechargeScoreIncrement(Date createTime, Long deptId, BigDecimal rechargeScore) {
if (createTime == null || deptId == null || rechargeScore == null) {
return;
}
@Override
public int updateAiVideoReportData(AiVideoReportData aiVideoReportData) {
return videoReportDataMapper.updateAiVideoReportData(aiVideoReportData);
}
@Override
public int deleteAiVideoReportDataByIds(String[] ids) {
return videoReportDataMapper.deleteAiVideoReportDataByIds(ids);
}
private static String formatDateKey(Date date) {
LocalDateTime ldt = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
return DATE_KEY_FORMAT.format(ldt);
String dateKey = new SimpleDateFormat("yyyyMMddHH").format(createTime);
aiVideoReportDataMapper.upsertRechargeScoreIncrement(dateKey, deptId, rechargeScore);
}
}

View File

@ -6,7 +6,6 @@ import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;
import com.ruoyi.common.constant.BalanceChangerConstants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -118,6 +117,6 @@ public class DeptChargeRefundServiceImpl implements IDeptChargeRefundService {
private static String buildOrderNum() {
String uuid = UUID.randomUUID().toString().replace("-", "").substring(0, 8);
String dateTime = new SimpleDateFormat("yyyyMMdd").format(new Date());
return BalanceChangerConstants.OrderNoPrefix.RECHARGE_REFUND_PREFIX + dateTime + uuid;
return "CG" + dateTime + uuid;
}
}

View File

@ -78,7 +78,9 @@ public class DeptUserScoreTransferTxService {
}
String orderNum = buildOrderNum();
aiUserService.addUserBalance(orderNum, user.getId(), amount.negate(), BalanceChangerConstants.DEPT_SCORE_RECLAIM, request.getRemark());
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) {
@ -86,7 +88,7 @@ public class DeptUserScoreTransferTxService {
}
BigDecimal deptBalAfter = getDeptBalance(deptId);
insertGroupRecord(orderNum, deptId, GroupBalanceChangeType.RECLAIM.getCode(), amount, deptBalAfter, request.getRemark());
insertGroupRecord(orderNum, deptId, GroupBalanceChangeType.RECLAIM.getCode(), amount, deptBalAfter, remark);
}
private AiUser requireUserWithDept(Long id) {
@ -142,6 +144,6 @@ public class DeptUserScoreTransferTxService {
private static String buildOrderNum() {
String uuid = UUID.randomUUID().toString().replace("-", "").substring(0, 8);
String dateTime = new SimpleDateFormat("yyyyMMdd").format(new Date());
return BalanceChangerConstants.OrderNoPrefix.ISSUE_RECLAIM_PREFIX + dateTime + uuid;
return "DU" + dateTime + uuid;
}
}

View File

@ -0,0 +1,107 @@
package com.ruoyi.system.service.subteam.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.ai.domain.AiChargeRefundOrder;
import com.ruoyi.ai.domain.AiGroupBalanceChangeRecord;
import com.ruoyi.ai.domain.AiOrder;
import com.ruoyi.ai.domain.AiBalanceChangeRecord;
import com.ruoyi.ai.mapper.AiChargeRefundOrderMapper;
import com.ruoyi.ai.mapper.AiGroupBalanceChangeRecordMapper;
import com.ruoyi.ai.mapper.AiOrderMapper;
import com.ruoyi.ai.mapper.AiBalanceChangeRecordMapper;
import com.ruoyi.common.core.domain.entity.AiUser;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.system.mapper.SysUserMapper;
import com.ruoyi.system.service.subteam.ISubteamScopeService;
import com.ruoyi.ai.mapper.AiUserMapper;
@Service
public class SubteamScopeServiceImpl implements ISubteamScopeService {
@Autowired
private SysUserMapper sysUserMapper;
@Autowired
private AiOrderMapper aiOrderMapper;
@Autowired
private AiChargeRefundOrderMapper aiChargeRefundOrderMapper;
@Autowired
private AiGroupBalanceChangeRecordMapper aiGroupBalanceChangeRecordMapper;
@Autowired
private AiBalanceChangeRecordMapper aiBalanceChangeRecordMapper;
@Autowired
private AiUserMapper aiUserMapper;
@Override
public Long currentTeamDeptId() {
Long deptId = SecurityUtils.getDeptId();
if (deptId == null || deptId <= 0) {
throw new ServiceException("当前账号未绑定团队,无法使用团队后台");
}
return deptId;
}
@Override
public void assertSysUserInTeam(Long sysUserId) {
Long teamDeptId = currentTeamDeptId();
SysUser u = sysUserMapper.selectUserById(sysUserId);
if (u == null || u.getDeptId() == null || !teamDeptId.equals(u.getDeptId())) {
throw new ServiceException("无权操作该用户");
}
}
@Override
public void assertAiUserInTeam(Long aiUserId) {
Long teamDeptId = currentTeamDeptId();
AiUser user = aiUserMapper.selectById(aiUserId);
if (user == null || user.getDeptId() == null || !teamDeptId.equals(user.getDeptId())) {
throw new ServiceException("无权操作该用户");
}
}
@Override
public void assertAiOrderBelongsToTeam(Long orderId) {
Long teamDeptId = currentTeamDeptId();
AiOrder o = aiOrderMapper.selectById(orderId);
if (o == null || o.getDeptId() == null || !teamDeptId.equals(o.getDeptId())) {
throw new ServiceException("无权查看该订单");
}
}
@Override
public void assertChargeRefundBelongsToTeam(Long orderPkId) {
Long teamDeptId = currentTeamDeptId();
AiChargeRefundOrder o = aiChargeRefundOrderMapper.selectAiChargeRefundOrderById(orderPkId);
if (o == null || o.getDeptId() == null || !teamDeptId.equals(o.getDeptId())) {
throw new ServiceException("无权查看该充值记录");
}
}
@Override
public void assertGroupBalanceRecordBelongsToTeam(String recordId) {
Long teamDeptId = currentTeamDeptId();
AiGroupBalanceChangeRecord r = aiGroupBalanceChangeRecordMapper.selectById(recordId);
if (r == null || r.getDeptId() == null || !teamDeptId.equals(r.getDeptId())) {
throw new ServiceException("无权查看该记录");
}
}
@Override
public void assertAiBalanceRecordVisible(Long recordId, Long teamDeptId) {
AiBalanceChangeRecord r = aiBalanceChangeRecordMapper.selectById(recordId);
if (r == null) {
throw new ServiceException("记录不存在");
}
AiUser u = aiUserMapper.selectAiUserById(r.getUserId());
if (u == null || u.getDeptId() == null || !teamDeptId.equals(u.getDeptId())) {
throw new ServiceException("无权查看该余额变动");
}
}
}

View File

@ -48,17 +48,17 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<include refid="selectAiBalanceChangeRecordVo"/>
<where>
and u.dept_id = #{deptId}
<if test="query.nickname != null and query.nickname != '' "> and u.nickname like concat('%', #{query.nickname}, '%') </if>
<if test="query.userId != null "> and r.user_id = #{query.userId}</if>
<if test="query.uuid != null "> and u.user_id = #{query.uuid}</if>
<if test="query.type != null "> and r.type = #{query.type}</if>
<if test="query.changeAmount != null "> and r.change_amount = #{query.changeAmount}</if>
<if test="query.resultAmount != null "> and r.result_amount = #{query.resultAmount}</if>
<if test="query.params.beginTime != null and query.params.beginTime != ''">
AND date_format(r.create_time,'%Y%m%d') &gt;= date_format(#{query.params.beginTime},'%Y%m%d')
<if test="q.nickname != null and q.nickname != '' "> and u.nickname like concat('%', #{q.nickname}, '%') </if>
<if test="q.userId != null "> and r.user_id = #{q.userId}</if>
<if test="q.uuid != null "> and u.user_id = #{q.uuid}</if>
<if test="q.type != null "> and r.type = #{q.type}</if>
<if test="q.changeAmount != null "> and r.change_amount = #{q.changeAmount}</if>
<if test="q.resultAmount != null "> and r.result_amount = #{q.resultAmount}</if>
<if test="q.params != null and q.params.beginTime != null and q.params.beginTime != ''">
AND date_format(r.create_time,'%Y%m%d') &gt;= date_format(#{q.params.beginTime},'%Y%m%d')
</if>
<if test="query.params.endTime != null and query.params.endTime != ''">
AND date_format(r.create_time,'%Y%m%d') &lt;= date_format(#{query.params.endTime},'%Y%m%d')
<if test="q.params != null and q.params.endTime != null and q.params.endTime != ''">
AND date_format(r.create_time,'%Y%m%d') &lt;= date_format(#{q.params.endTime},'%Y%m%d')
</if>
</where>
order by r.id desc

View File

@ -93,6 +93,3 @@ CREATE TABLE `ai_charge_refund_order` (
COMMENT='团队(部门)充值退款订单表'
COLLATE='utf8mb4_unicode_ci'
ENGINE=InnoDB;
ALTER TABLE `ai_user`
ADD INDEX `dept_id` (`dept_id`);

View File

@ -193,3 +193,5 @@ values('团队(部门)对应火山引擎配置删除', @parentId, '4', '#',
insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values('团队(部门)对应火山引擎配置导出', @parentId, '5', '#', '', 1, 0, 'F', '0', '0', 'ai:config:export', '#', 'admin', sysdate(), '', null, '');
ALTER TABLE `byteai`.`ai_balance_change_record`
ADD COLUMN `dept_id` bigint NULL COMMENT '部门ID' AFTER `remark`;