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" size="mini"
@click="handleAdd" @click="handleAdd"
v-hasPermi="['system:dept:add']" v-hasPermi="['system:dept:add']"
>新增</el-button> >新增二级部门</el-button>
</el-col> </el-col>
<el-col :span="1.5"> <el-col :span="1.5">
<el-button <el-button
@ -57,10 +57,10 @@
:tree-props="{children: 'children', hasChildren: 'hasChildren'}" :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
> >
<el-table-column prop="deptName" label="部门名称" width="260"></el-table-column> <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="orderNum" label="排序" width="200"></el-table-column>
<el-table-column prop="balance" label="剩余积分" width="200" align="right"> <el-table-column prop="maxUserCount" label="账号上限" width="100" align="center">
<template slot-scope="scope"> <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> </template>
</el-table-column> </el-table-column>
<el-table-column prop="status" label="状态" width="100"> <el-table-column prop="status" label="状态" width="100">
@ -68,20 +68,13 @@
<dict-tag :options="dict.type.sys_normal_disable" :value="scope.row.status"/> <dict-tag :options="dict.type.sys_normal_disable" :value="scope.row.status"/>
</template> </template>
</el-table-column> </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"> <template slot-scope="scope">
<span>{{ parseTime(scope.row.createTime) }}</span> <span>{{ parseTime(scope.row.createTime) }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width"> <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope"> <template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-plus"
@click="handleAdd(scope.row)"
v-hasPermi="['system:dept:add']"
>新增</el-button>
<el-button <el-button
size="mini" size="mini"
type="text" type="text"
@ -89,6 +82,14 @@
@click="handleUpdate(scope.row)" @click="handleUpdate(scope.row)"
v-hasPermi="['system:dept:edit']" v-hasPermi="['system:dept:edit']"
>修改</el-button> >修改</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 <el-button
v-if="scope.row.parentId != 0" v-if="scope.row.parentId != 0"
size="mini" size="mini"
@ -97,20 +98,6 @@
@click="handleDelete(scope.row)" @click="handleDelete(scope.row)"
v-hasPermi="['system:dept:remove']" v-hasPermi="['system:dept:remove']"
>删除</el-button> >删除</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> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@ -133,31 +120,31 @@
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="显示排序" prop="orderNum"> <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-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-row> <el-row>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="负责人" prop="leader"> <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-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="联系电话" prop="phone"> <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-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-row> <el-row>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="邮箱" prop="email"> <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-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="部门状态"> <el-form-item label="部门状态">
<el-radio-group v-model="form.status"> <el-radio-group v-model="form.status" :disabled="isFirstLevelEditForm">
<el-radio <el-radio
v-for="dict in dict.type.sys_normal_disable" v-for="dict in dict.type.sys_normal_disable"
:key="dict.value" :key="dict.value"
@ -167,6 +154,25 @@
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </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-row v-if="isSecondLevelCompanyForm">
<el-col :span="24"> <el-col :span="24">
<el-form-item label="Byte API Key"> <el-form-item label="Byte API Key">
@ -230,95 +236,11 @@
</el-row> </el-row>
</el-form> </el-form>
<div slot="footer" class="dialog-footer"> <div slot="footer" class="dialog-footer">
<span v-if="isFirstLevelEditForm" class="form-tip">一级部门仅允许修改名称</span>
<el-button type="primary" @click="submitForm"> </el-button> <el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button> <el-button @click="cancel"> </el-button>
</div> </div>
</el-dialog> </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> </div>
</template> </template>
@ -345,23 +267,15 @@
color: #909399; color: #909399;
line-height: 1.5; line-height: 1.5;
} }
.edit-score-input-number { .form-tip {
width: 100%; margin-right: 16px;
color: #e6a23c;
font-size: 12px;
} }
</style> </style>
<script> <script>
import { listDept, getDept, delDept, addDept, updateDept, listDeptExcludeChild, chargeRefundDept, editScore } from "@/api/system/dept" import { listDept, getDept, delDept, addDept, updateDept, listDeptExcludeChild } from "@/api/system/dept"
import {
WESTERN_MONEY_MAX,
sanitizeMoneyDigits,
formatMoneyWesternDisplay,
moneyStringToNumber,
formatMoneyWesternFinal,
sanitizeIntDigits,
formatIntWesternDisplay,
intStringToNumber
} from "@/utils/westernNumberFormat"
import Treeselect from "@riophae/vue-treeselect" import Treeselect from "@riophae/vue-treeselect"
import "@riophae/vue-treeselect/dist/vue-treeselect.css" import "@riophae/vue-treeselect/dist/vue-treeselect.css"
@ -394,76 +308,8 @@ export default {
}, },
// //
form: {}, form: {},
originalForm: {},
modelParamRows: [{ label: '', value: '' }], 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: { rules: {
parentId: [ parentId: [
@ -506,9 +352,35 @@ export default {
return true return true
} }
return false return false
},
isFirstLevelEditForm() {
return this.form.deptId !== undefined && this.isFirstLevelRow(this.form)
} }
}, },
methods: { 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() { syncModelRowsFromForm() {
this.modelParamRows = [{ label: '', value: '' }] this.modelParamRows = [{ label: '', value: '' }]
const raw = this.form.modelParm const raw = this.form.modelParm
@ -578,11 +450,13 @@ export default {
leader: undefined, leader: undefined,
phone: undefined, phone: undefined,
email: undefined, email: undefined,
maxUserCount: undefined,
byteApiKey: undefined, byteApiKey: undefined,
project: undefined, project: undefined,
modelParm: undefined, modelParm: undefined,
status: "0" status: "0"
} }
this.originalForm = {}
this.modelParamRows = [{ label: '', value: '' }] this.modelParamRows = [{ label: '', value: '' }]
this.resetForm("form") this.resetForm("form")
}, },
@ -598,13 +472,17 @@ export default {
/** 新增按钮操作 */ /** 新增按钮操作 */
handleAdd(row) { handleAdd(row) {
this.reset() this.reset()
if (row != undefined) { if (row !== undefined) {
if (!this.isFirstLevelRow(row)) {
this.$modal.msgError("仅允许在一级部门下新增二级部门")
return
}
this.form.parentId = row.deptId this.form.parentId = row.deptId
} }
this.open = true this.open = true
this.title = "添加部门" this.title = "添加二级部门"
listDept().then(response => { 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() this.reset()
getDept(row.deptId).then(response => { getDept(row.deptId).then(response => {
this.form = response.data this.form = response.data
this.originalForm = { ...response.data }
this.syncModelRowsFromForm() this.syncModelRowsFromForm()
this.open = true this.open = true
this.title = "修改部门" this.title = "修改部门"
listDeptExcludeChild(row.deptId).then(response => { 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) { if (this.deptOptions.length == 0) {
const noResultsOptions = { deptId: this.form.parentId, deptName: this.form.parentName, children: [] } const noResultsOptions = { deptId: this.form.parentId, deptName: this.form.parentName, children: [] }
this.deptOptions.push(noResultsOptions) this.deptOptions.push(noResultsOptions)
@ -637,7 +517,24 @@ export default {
this.$refs["form"].validate(valid => { this.$refs["form"].validate(valid => {
if (valid) { if (valid) {
this.buildModelParmPayload() 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.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 => { updateDept(this.form).then(response => {
this.$modal.msgSuccess("修改成功") this.$modal.msgSuccess("修改成功")
this.open = false 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) { handleDelete(row) {
this.$modal.confirm('是否确认删除名称为"' + row.deptName + '"的数据项?').then(function() { this.$modal.confirm('是否确认删除名称为"' + row.deptName + '"的数据项?').then(function() {

View File

@ -44,20 +44,7 @@
inputType="password" inputType="password"
:placeholder="`${$t('common.passwordPlaceholder')}`" /> :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"> <div class="login-submit">
<mf-button
size="large"
@click="showRegister">
{{ $t('common.register') }}
</mf-button>
<mf-button <mf-button
size="large" size="large"
type="primary" type="primary"
@ -67,25 +54,10 @@
</mf-button> </mf-button>
</div> </div>
</mf-dialog> </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> </div>
</template> </template>
<script> <script>
import Forgot from './Forgot.vue'
import Register from './Register.vue'
import { mapGetters } from 'vuex' import { mapGetters } from 'vuex'
import i18n from '@/lang/i18n' import i18n from '@/lang/i18n'
@ -93,22 +65,16 @@ export default {
data() { data() {
return { return {
email: '', email: '',
forgotVisible: false,
emailVisible: false, emailVisible: false,
registerVisible: false,
loading: false, loading: false,
username: '', username: '',
password: '' password: ''
} }
}, },
props: { props: {
visible: Boolean, visible: Boolean
register: Boolean
},
components: {
Forgot,
Register
}, },
components: {},
computed: { computed: {
...mapGetters(['lang']) ...mapGetters(['lang'])
}, },
@ -121,10 +87,6 @@ export default {
// } // }
this.username = "" this.username = ""
this.password = "" this.password = ""
let { inviteCode } = this.$route.query || {}
if (inviteCode) {
this.showRegister()
}
}, },
methods: { methods: {
cancel() { cancel() {
@ -132,24 +94,12 @@ export default {
this.password = '' this.password = ''
this.$emit('cancel') this.$emit('cancel')
}, },
showRegister() {
this.registerVisible = true
this.$emit('cancel')
},
changeLang(value) { changeLang(value) {
if (value != this.lang) { if (value != this.lang) {
this.$store.dispatch('main/setLanguage', value) this.$store.dispatch('main/setLanguage', value)
i18n.global.locale = value i18n.global.locale = value
} }
}, },
back() {
this.forgotVisible = false
this.$emit('open')
},
backFormRegister() {
this.registerVisible = false
this.$emit('open')
},
login() { login() {
if (!this.username) { if (!this.username) {
this.$message.error(this.$t('common.userEmailPlaceholder')) this.$message.error(this.$t('common.userEmailPlaceholder'))
@ -191,10 +141,6 @@ export default {
.catch((_) => { .catch((_) => {
this.loading = false this.loading = false
}) })
},
showForgot() {
this.forgotVisible = true
this.$emit('cancel')
} }
} }
} }
@ -324,36 +270,8 @@ export default {
justify-content: center; justify-content: center;
margin-top: 30px; margin-top: 30px;
.mf-button { .mf-button {
width: 160px; width: 220px;
border-radius: 10px; 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> </div>
<Login <Login
:register="!$datas.isEmpty(inviteCode)"
:visible="showLogin" :visible="showLogin"
@open="openLogin" @open="openLogin"
@cancel="cancelLogin" /> @cancel="cancelLogin" />
@ -118,7 +117,6 @@ export default {
} }
], ],
publishVisible: false, publishVisible: false,
inviteCode: this.$route.query?.inviteCode,
userVisible: false, userVisible: false,
logoUrl: null logoUrl: null
} }
@ -179,9 +177,6 @@ export default {
} }
}, },
mounted() { mounted() {
if (this.inviteCode) {
this.openLogin()
}
this.getLogo() this.getLogo()
if (getToken()) { if (getToken()) {
this.$store.dispatch('user/getInfo').catch(() => {}) 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; 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-form-item label="${comment}" prop="${column.javaField}">
<el-input <el-input
v-model="queryParams.${column.javaField}" v-model="queryParams.${column.javaField}"
placeholder="请输入${comment}" placeholder="请输入ID"
clearable clearable
@keyup.enter="handleQuery" @keyup.enter="handleQuery"
/> />

View File

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

View File

@ -1,42 +1,44 @@
package com.ruoyi.ai.domain; package com.ruoyi.ai.domain;
import java.io.Serializable;
import java.util.Date;
import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data; 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 @Data
@TableName("ai_dept_ark_config") @TableName("ai_dept_ark_config")
public class AiDeptArkConfig implements Serializable { public class AiDeptArkConfig extends BaseEntity {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** $column.columnComment */
@TableId(type = IdType.AUTO) @TableId(type = IdType.AUTO)
private Long id; private String id;
/** 部门ID */
@Excel(name = "部门ID")
private Long deptId; private Long deptId;
/** 模型参数 JSON */ /** 视频模型列表JSON(label+value) */
@Excel(name = "视频模型列表JSON(label+value)")
private String modelParm; private String modelParm;
/** Byte project加密 */
@Excel(name = "Byte project加密")
private String project; private String project;
/** Byte API Key加密 */
@Excel(name = "Byte API Key加密")
private String byteApiKey; 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; package com.ruoyi.ai.domain;
import java.io.Serializable;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Date; import lombok.Data;
import org.apache.commons.lang3.builder.ToStringBuilder;
import com.baomidou.mybatisplus.annotation.EnumValue; import org.apache.commons.lang3.builder.ToStringStyle;
import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.annotation.Excel; 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 @Data
@TableName("ai_group_balance_change_record") @TableName("ai_group_balance_change_record")
public class AiGroupBalanceChangeRecord implements Serializable { public class AiGroupBalanceChangeRecord extends BaseEntity {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** $column.columnComment */
@TableId(type = IdType.AUTO) @TableId(type = IdType.AUTO)
private Long id; private String id;
/** 关联订单号 */ /** 关联(充值/退款)订单号 */
@Excel(name = "关联(充值/退款)订单号")
private String relationOrderNo; private String relationOrderNo;
/** 部门ID */
@Excel(name = "部门ID")
private Long deptId; private Long deptId;
/** 类型0-充值 1-退款 2-下发 3-消费 4-手动修改 */ /** 操作类型0-充值、1-退款、2-下发、3-回收、4-手动修改) */
// GroupBalanceChangeType @Excel(name = "操作类型", readConverterExp = "0=-充值、1-退款、2-下发、3-回收、4-手动修改")
private Integer type; private Long type;
/** 变更金额 */
@Excel(name = "变更金额")
private BigDecimal changeAmount; private BigDecimal changeAmount;
/** 变更后金额 */
@Excel(name = "变更后金额")
private BigDecimal resultAmount; 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; 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.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat; import java.math.BigDecimal;
import com.ruoyi.common.annotation.Excel;
import lombok.Data; 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 @Data
@TableName("ai_video_report_data") @TableName("ai_video_report_data")
public class AiVideoReportData implements Serializable { public class AiVideoReportData extends BaseEntity {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** 主键 */ /** $column.columnComment */
@TableId(type = IdType.AUTO) @TableId(type = IdType.AUTO)
private Long id; private String id;
/** 统计日期键varchar */ /** 统计时间到小时yyyyMMddHH */
@Excel(name = "统计时间,到小时('%Y-%m-%d %H')")
private String dateKey; private String dateKey;
/** 查询参数统计日期yyyyMMdd */
private String statDate;
/** 部门ID */ /** 部门ID */
@Excel(name = "部门ID")
private Long deptId; private Long deptId;
/** 用户ID */ /** 用户ID用户表的ID延用其他表设计 */
@Excel(name = "用户ID用户表的ID延用其他表设计 ")
private Long userId; private Long userId;
/** 积分/分数统计 */ /** 消耗积分,按任务创建时间统计 */
@Excel(name = "消耗积分,按任务创建时间统计")
private BigDecimal score; private BigDecimal score;
/** 订单数 */ /** 实际订单数,只统计已生成成功的任务 */
@Excel(name = "实际订单数,只统计已生成成功的任务")
private Long orderCount; private Long orderCount;
/** 消耗 tokens */ /** 三方消耗tokens数量按任务创建时间统计 */
@Excel(name = "三方消耗tokens数量按任务创建时间统计")
private Long useTokens; private Long useTokens;
/** 充值积分 */ /** 实际充值积分(充值-退款) */
@Excel(name = "实际充值积分(充值-退款)")
private BigDecimal rechargeScore; private BigDecimal rechargeScore;
/** 部门名称(联表字段) */ /** 团队名称(查询结果展示字段) */
@TableField(exist = false)
private String deptName; private String deptName;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") /** 查询日期yyyyMMdd */
private Date createTime; @TableField(exist = false)
private String statDate;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
} }

View File

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

View File

@ -1,18 +1,24 @@
package com.ruoyi.ai.mapper; package com.ruoyi.ai.mapper;
import java.util.List;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.ai.domain.AiChargeRefundOrder; import com.ruoyi.ai.domain.AiChargeRefundOrder;
import java.util.List;
/** /**
* 充值/退款订单 Mapper * 团队部门充值退款订单Mapper接口
*
* @author shi
* @date 2026-04-17
*/ */
public interface AiChargeRefundOrderMapper extends BaseMapper<AiChargeRefundOrder> { public interface AiChargeRefundOrderMapper extends BaseMapper<AiChargeRefundOrder> {
/** /**
* 查询充值/退款订单列表 * 列表关联团队名称支持按 deptName 模糊查
*
* @param aiChargeRefundOrder 查询条件
* @return 订单列表
*/ */
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; package com.ruoyi.ai.mapper;
import java.util.List;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.ai.domain.AiDeptArkConfig; import com.ruoyi.ai.domain.AiDeptArkConfig;
import java.util.List;
/** /**
* 部门方舟配置 Mapper * 团队部门对应火山引擎配置Mapper接口
*
* @author shi
* @date 2026-04-17
*/ */
public interface AiDeptArkConfigMapper extends BaseMapper<AiDeptArkConfig> { 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; package com.ruoyi.ai.mapper;
import java.util.List;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.ai.domain.AiGroupBalanceChangeRecord; import com.ruoyi.ai.domain.AiGroupBalanceChangeRecord;
import java.util.List;
/** /**
* 集团余额变动记录 Mapper * 团队部门余额变动Mapper接口
*
* @author shi
* @date 2026-04-17
*/ */
public interface AiGroupBalanceChangeRecordMapper extends BaseMapper<AiGroupBalanceChangeRecord> { 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; package com.ruoyi.ai.mapper;
import java.util.List;
import java.math.BigDecimal;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.ai.domain.AiVideoReportData; import com.ruoyi.ai.domain.AiVideoReportData;
import com.ruoyi.common.core.dto.DeptSummaryDTO;
import com.ruoyi.system.domain.subteam.SubteamVideoMetrics; 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.Param;
import org.apache.ibatis.annotations.Select;
/** /**
* 视频报表数据 Mapper * AI视频生成统计数据作为其他统计报的数据源Mapper接口
*
* @author shi
* @date 2026-04-17
*/ */
public interface AiVideoReportDataMapper extends BaseMapper<AiVideoReportData> { 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("startDay") String startDay,
@Param("endDay") String endDay); @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("deptId") Long deptId,
@Param("userId") Long userId, @Param("userId") Long userId,
@Param("score") BigDecimal score, @Param("score") BigDecimal score,
@Param("orderCount") Long orderCount, @Param("orderCount") Long orderCount,
@Param("useTokens") Long useTokens); @Param("useTokens") Long useTokens);
List<AiVideoReportData> selectTeamDailyConsumeList( /**
@Param("statDate") String statDate, * date_key, dept_id, user_id=0聚合累加充值积分统计
@Param("deptName") String deptName); *
* @param dateKey 小时KeyyyyyMMddHH
List<AiVideoReportData> selectAiVideoReportDataList(AiVideoReportData aiVideoReportData); * @param deptId 部门ID
* @param rechargeScore 充值积分增量
AiVideoReportData selectAiVideoReportDataById(String id); * @return 影响行数
*/
int insertAiVideoReportData(AiVideoReportData aiVideoReportData); int upsertRechargeScoreIncrement(@Param("dateKey") String dateKey,
@Param("deptId") Long deptId,
int updateAiVideoReportData(AiVideoReportData aiVideoReportData); @Param("rechargeScore") BigDecimal rechargeScore);
int deleteAiVideoReportDataByIds(String[] ids);
} }

View File

@ -1,28 +1,71 @@
package com.ruoyi.ai.service; package com.ruoyi.ai.service;
import com.ruoyi.ai.domain.AiChargeRefundOrder;
import java.util.List; 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 { public interface IAiChargeRefundOrderService {
AiChargeRefundOrder selectById(Long id); /**
* 查询团队部门充值退款订单
int insert(AiChargeRefundOrder entity); *
* @param id 团队部门充值退款订单主键
int updateById(AiChargeRefundOrder entity); * @return 团队部门充值退款订单
*/
int deleteById(Long id);
List<AiChargeRefundOrder> selectAiChargeRefundOrderList(AiChargeRefundOrder aiChargeRefundOrder);
AiChargeRefundOrder selectAiChargeRefundOrderById(Long id); 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); int insertAiChargeRefundOrder(AiChargeRefundOrder aiChargeRefundOrder);
/**
* 修改团队部门充值退款订单
*
* @param aiChargeRefundOrder 团队部门充值退款订单
* @return 结果
*/
int updateAiChargeRefundOrder(AiChargeRefundOrder aiChargeRefundOrder); int updateAiChargeRefundOrder(AiChargeRefundOrder aiChargeRefundOrder);
/**
* 批量删除团队部门充值退款订单
*
* @param ids 需要删除的团队部门充值退款订单主键集合
* @return 结果
*/
int deleteAiChargeRefundOrderByIds(Long[] ids); int deleteAiChargeRefundOrderByIds(Long[] ids);
/**
* 删除团队部门充值退款订单信息
*
* @param id 团队部门充值退款订单主键
* @return 结果
*/
int deleteAiChargeRefundOrderById(Long id);
} }

View File

@ -1,28 +1,71 @@
package com.ruoyi.ai.service; package com.ruoyi.ai.service;
import com.ruoyi.ai.domain.AiDeptArkConfig;
import java.util.List; 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 { public interface IAiDeptArkConfigService {
AiDeptArkConfig selectById(Long id); /**
* 查询团队部门对应火山引擎配置
int insert(AiDeptArkConfig entity); *
* @param id 团队部门对应火山引擎配置主键
int updateById(AiDeptArkConfig entity); * @return 团队部门对应火山引擎配置
*/
int deleteById(Long id);
List<AiDeptArkConfig> selectAiDeptArkConfigList(AiDeptArkConfig aiDeptArkConfig);
AiDeptArkConfig selectAiDeptArkConfigById(String id); 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); int insertAiDeptArkConfig(AiDeptArkConfig aiDeptArkConfig);
/**
* 修改团队部门对应火山引擎配置
*
* @param aiDeptArkConfig 团队部门对应火山引擎配置
* @return 结果
*/
int updateAiDeptArkConfig(AiDeptArkConfig aiDeptArkConfig); int updateAiDeptArkConfig(AiDeptArkConfig aiDeptArkConfig);
/**
* 批量删除团队部门对应火山引擎配置
*
* @param ids 需要删除的团队部门对应火山引擎配置主键集合
* @return 结果
*/
int deleteAiDeptArkConfigByIds(String[] ids); int deleteAiDeptArkConfigByIds(String[] ids);
/**
* 删除团队部门对应火山引擎配置信息
*
* @param id 团队部门对应火山引擎配置主键
* @return 结果
*/
int deleteAiDeptArkConfigById(String id);
} }

View File

@ -1,29 +1,71 @@
package com.ruoyi.ai.service; package com.ruoyi.ai.service;
import com.ruoyi.ai.domain.AiGroupBalanceChangeRecord;
import java.util.List; 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 { public interface IAiGroupBalanceChangeRecordService {
AiGroupBalanceChangeRecord selectById(Long id); /**
* 查询团队部门余额变动
int insert(AiGroupBalanceChangeRecord entity); *
* @param id 团队部门余额变动主键
int updateById(AiGroupBalanceChangeRecord entity); * @return 团队部门余额变动
*/
int deleteById(Long id);
List<AiGroupBalanceChangeRecord> selectAiGroupBalanceChangeRecordList(
AiGroupBalanceChangeRecord aiGroupBalanceChangeRecord);
AiGroupBalanceChangeRecord selectAiGroupBalanceChangeRecordById(String id); 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); int insertAiGroupBalanceChangeRecord(AiGroupBalanceChangeRecord aiGroupBalanceChangeRecord);
/**
* 修改团队部门余额变动
*
* @param aiGroupBalanceChangeRecord 团队部门余额变动
* @return 结果
*/
int updateAiGroupBalanceChangeRecord(AiGroupBalanceChangeRecord aiGroupBalanceChangeRecord); int updateAiGroupBalanceChangeRecord(AiGroupBalanceChangeRecord aiGroupBalanceChangeRecord);
/**
* 批量删除团队部门余额变动
*
* @param ids 需要删除的团队部门余额变动主键集合
* @return 结果
*/
int deleteAiGroupBalanceChangeRecordByIds(String[] ids); int deleteAiGroupBalanceChangeRecordByIds(String[] ids);
/**
* 删除团队部门余额变动信息
*
* @param id 团队部门余额变动主键
* @return 结果
*/
int deleteAiGroupBalanceChangeRecordById(String id);
} }

View File

@ -1,51 +1,107 @@
package com.ruoyi.ai.service; 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.util.List;
import java.math.BigDecimal;
import java.util.Date; 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 { public interface IAiVideoReportDataService {
AiVideoReportData selectById(Long id);
int insert(AiVideoReportData entity);
DeptSummaryDTO getSevenDayDeptSummaryData(Long deptId);
/** /**
* 按部门查询团队每日消耗 * 查询AI视频生成统计数据作为其他统计报的数据源
* *
* @param statDate 统计日期yyyyMMdd * @param id AI视频生成统计数据作为其他统计报的数据源主键
* @param deptId 部门ID * @return AI视频生成统计数据作为其他统计报的数据源
* @return 每日消耗列表 */
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); List<AiVideoReportData> selectTeamDailyConsumeByDeptId(String statDate, Long deptId);
/** /**
* 同步视频消耗增量 * 按视频订单成功结果回写统计来源表按小时部门账号聚合累加
* *
* @param createTime 订单创建时间 * @param createTime 任务创建时间
* @param deptId 部门ID * @param deptId 部门ID
* @param userId 用户ID * @param userId 账号ID
* @param score 消耗积分 * @param score 消耗积分增量
* @param useTokens 消耗token * @param useTokens 三方tokens增量
*/ */
void syncVideoConsumeIncrement(Date createTime, Long deptId, Long userId, BigDecimal score, Long useTokens); void syncVideoConsumeIncrement(Date createTime, Long deptId, Long userId, BigDecimal score, Long useTokens);
List<AiVideoReportData> selectTeamDailyConsumeList(String statDate, String deptName); /**
* 按充值/退款成功结果回写统计来源表按小时部门聚合累加
List<AiVideoReportData> selectAiVideoReportDataList(AiVideoReportData aiVideoReportData); *
* @param createTime 订单创建时间
AiVideoReportData selectAiVideoReportDataById(String id); * @param deptId 部门ID
* @param rechargeScore 实际充值积分增量充值为正退款为负
int insertAiVideoReportData(AiVideoReportData aiVideoReportData); */
void syncRechargeScoreIncrement(Date createTime, Long deptId, BigDecimal rechargeScore);
int updateAiVideoReportData(AiVideoReportData aiVideoReportData);
int deleteAiVideoReportDataByIds(String[] ids);
} }

View File

@ -1,15 +1,30 @@
package com.ruoyi.ai.service.impl; 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.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import com.ruoyi.ai.domain.AiChargeRefundOrder;
import com.ruoyi.ai.mapper.AiChargeRefundOrderMapper; 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 com.ruoyi.ai.service.IAiChargeRefundOrderService;
import java.util.List;
/** /**
* 充值/退款订单 Service 实现 * 团队部门充值退款订单Service业务层处理
*
* @author shi
* @date 2026-04-17
*/ */
@Service @Service
public class AiChargeRefundOrderServiceImpl implements IAiChargeRefundOrderService { public class AiChargeRefundOrderServiceImpl implements IAiChargeRefundOrderService {
@ -17,55 +32,151 @@ public class AiChargeRefundOrderServiceImpl implements IAiChargeRefundOrderServi
@Autowired @Autowired
private AiChargeRefundOrderMapper aiChargeRefundOrderMapper; private AiChargeRefundOrderMapper aiChargeRefundOrderMapper;
@Autowired
private IAiVideoReportDataService aiVideoReportDataService;
/**
* 查询团队部门充值退款订单
*
* @param id 团队部门充值退款订单主键
* @return 团队部门充值退款订单
*/
@Override @Override
public AiChargeRefundOrder selectById(Long id) { public AiChargeRefundOrder selectAiChargeRefundOrderById(Long id) {
return aiChargeRefundOrderMapper.selectById(id); return aiChargeRefundOrderMapper.selectAiChargeRefundOrderById(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);
} }
/**
* 查询团队部门充值退款订单列表
*
* @param aiChargeRefundOrder 团队部门充值退款订单
* @return 团队部门充值退款订单
*/
@Override @Override
public List<AiChargeRefundOrder> selectAiChargeRefundOrderList(AiChargeRefundOrder aiChargeRefundOrder) { public List<AiChargeRefundOrder> selectAiChargeRefundOrderList(AiChargeRefundOrder aiChargeRefundOrder) {
return aiChargeRefundOrderMapper.selectAiChargeRefundOrderList(aiChargeRefundOrder); return aiChargeRefundOrderMapper.selectAiChargeRefundOrderList(aiChargeRefundOrder);
} }
/**
* 分页查询团队部门充值退款订单列表
*
* @param aiChargeRefundOrder 团队部门充值退款订单
* @return 团队部门充值退款订单
*/
@Override @Override
public AiChargeRefundOrder selectAiChargeRefundOrderById(Long id) { public IPage<AiChargeRefundOrder> selectAiChargeRefundOrderPage(Page page, AiChargeRefundOrder aiChargeRefundOrder) {
return aiChargeRefundOrderMapper.selectById(id); 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 @Override
public int insertAiChargeRefundOrder(AiChargeRefundOrder aiChargeRefundOrder) { 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 @Override
public int updateAiChargeRefundOrder(AiChargeRefundOrder aiChargeRefundOrder) { 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 @Override
public int deleteAiChargeRefundOrderByIds(Long[] ids) { public int deleteAiChargeRefundOrderByIds(Long[] ids)
int rows = 0; {
if (ids == null) { return aiChargeRefundOrderMapper.deleteAiChargeRefundOrderByIds(ids);
return rows; }
/**
* 删除团队部门充值退款订单信息
*
* @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; 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.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import com.ruoyi.ai.domain.AiDeptArkConfig;
import com.ruoyi.ai.mapper.AiDeptArkConfigMapper; import com.ruoyi.ai.mapper.AiDeptArkConfigMapper;
import com.ruoyi.ai.domain.AiDeptArkConfig;
import com.ruoyi.ai.service.IAiDeptArkConfigService; import com.ruoyi.ai.service.IAiDeptArkConfigService;
import java.util.List;
/** /**
* 部门方舟配置 Service 实现 * 团队部门对应火山引擎配置Service业务层处理
*
* @author shi
* @date 2026-04-17
*/ */
@Service @Service
public class AiDeptArkConfigServiceImpl implements IAiDeptArkConfigService { public class AiDeptArkConfigServiceImpl implements IAiDeptArkConfigService {
@ -17,48 +25,89 @@ public class AiDeptArkConfigServiceImpl implements IAiDeptArkConfigService {
@Autowired @Autowired
private AiDeptArkConfigMapper aiDeptArkConfigMapper; private AiDeptArkConfigMapper aiDeptArkConfigMapper;
/**
* 查询团队部门对应火山引擎配置
*
* @param id 团队部门对应火山引擎配置主键
* @return 团队部门对应火山引擎配置
*/
@Override @Override
public AiDeptArkConfig selectById(Long id) { public AiDeptArkConfig selectAiDeptArkConfigById(String id) {
return aiDeptArkConfigMapper.selectById(id); return aiDeptArkConfigMapper.selectById(id);
} }
@Override /**
public int insert(AiDeptArkConfig entity) { * 查询团队部门对应火山引擎配置列表
return aiDeptArkConfigMapper.insert(entity); *
} * @param aiDeptArkConfig 团队部门对应火山引擎配置
* @return 团队部门对应火山引擎配置
@Override */
public int updateById(AiDeptArkConfig entity) {
return aiDeptArkConfigMapper.updateById(entity);
}
@Override
public int deleteById(Long id) {
return aiDeptArkConfigMapper.deleteById(id);
}
@Override @Override
public List<AiDeptArkConfig> selectAiDeptArkConfigList(AiDeptArkConfig aiDeptArkConfig) { 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 @Override
public AiDeptArkConfig selectAiDeptArkConfigById(String id) { public IPage<AiDeptArkConfig> selectAiDeptArkConfigPage(Page page, AiDeptArkConfig aiDeptArkConfig) {
return aiDeptArkConfigMapper.selectAiDeptArkConfigById(id); LambdaQueryWrapper<AiDeptArkConfig> query = Wrappers.lambdaQuery(aiDeptArkConfig);
return aiDeptArkConfigMapper.selectPage(page, query);
} }
/**
* 新增团队部门对应火山引擎配置
*
* @param aiDeptArkConfig 团队部门对应火山引擎配置
* @return 结果
*/
@Override @Override
public int insertAiDeptArkConfig(AiDeptArkConfig aiDeptArkConfig) { 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 @Override
public int updateAiDeptArkConfig(AiDeptArkConfig aiDeptArkConfig) { 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 @Override
public int deleteAiDeptArkConfigByIds(String[] ids) { public int deleteAiDeptArkConfigByIds(String[] ids)
return aiDeptArkConfigMapper.deleteAiDeptArkConfigByIds(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; 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.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import com.ruoyi.ai.domain.AiGroupBalanceChangeRecord;
import com.ruoyi.ai.mapper.AiGroupBalanceChangeRecordMapper; import com.ruoyi.ai.mapper.AiGroupBalanceChangeRecordMapper;
import com.ruoyi.ai.domain.AiGroupBalanceChangeRecord;
import com.ruoyi.ai.service.IAiGroupBalanceChangeRecordService; import com.ruoyi.ai.service.IAiGroupBalanceChangeRecordService;
import java.util.List;
/** /**
* 集团余额变动记录 Service 实现 * 团队部门余额变动Service业务层处理
*
* @author shi
* @date 2026-04-17
*/ */
@Service @Service
public class AiGroupBalanceChangeRecordServiceImpl implements IAiGroupBalanceChangeRecordService { public class AiGroupBalanceChangeRecordServiceImpl implements IAiGroupBalanceChangeRecordService {
@ -17,49 +24,87 @@ public class AiGroupBalanceChangeRecordServiceImpl implements IAiGroupBalanceCha
@Autowired @Autowired
private AiGroupBalanceChangeRecordMapper aiGroupBalanceChangeRecordMapper; private AiGroupBalanceChangeRecordMapper aiGroupBalanceChangeRecordMapper;
/**
* 查询团队部门余额变动
*
* @param id 团队部门余额变动主键
* @return 团队部门余额变动
*/
@Override @Override
public AiGroupBalanceChangeRecord selectById(Long id) { public AiGroupBalanceChangeRecord selectAiGroupBalanceChangeRecordById(String id) {
return aiGroupBalanceChangeRecordMapper.selectById(id); return aiGroupBalanceChangeRecordMapper.selectById(id);
} }
/**
* 查询团队部门余额变动列表
*
* @param aiGroupBalanceChangeRecord 团队部门余额变动
* @return 团队部门余额变动
*/
@Override @Override
public int insert(AiGroupBalanceChangeRecord entity) { public List<AiGroupBalanceChangeRecord> selectAiGroupBalanceChangeRecordList(AiGroupBalanceChangeRecord aiGroupBalanceChangeRecord) {
return aiGroupBalanceChangeRecordMapper.insert(entity); LambdaQueryWrapper<AiGroupBalanceChangeRecord> query = Wrappers.lambdaQuery(aiGroupBalanceChangeRecord);
query.orderByDesc(AiGroupBalanceChangeRecord::getId);
return aiGroupBalanceChangeRecordMapper.selectList(query);
} }
/**
* 分页查询团队部门余额变动列表
*
* @param aiGroupBalanceChangeRecord 团队部门余额变动
* @return 团队部门余额变动
*/
@Override @Override
public int updateById(AiGroupBalanceChangeRecord entity) { public IPage<AiGroupBalanceChangeRecord> selectAiGroupBalanceChangeRecordPage(Page page, AiGroupBalanceChangeRecord aiGroupBalanceChangeRecord) {
return aiGroupBalanceChangeRecordMapper.updateById(entity); LambdaQueryWrapper<AiGroupBalanceChangeRecord> query = Wrappers.lambdaQuery(aiGroupBalanceChangeRecord);
} return aiGroupBalanceChangeRecordMapper.selectPage(page, query);
@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);
} }
/**
* 新增团队部门余额变动
*
* @param aiGroupBalanceChangeRecord 团队部门余额变动
* @return 结果
*/
@Override @Override
public int insertAiGroupBalanceChangeRecord(AiGroupBalanceChangeRecord aiGroupBalanceChangeRecord) { public int insertAiGroupBalanceChangeRecord(AiGroupBalanceChangeRecord aiGroupBalanceChangeRecord) {
return aiGroupBalanceChangeRecordMapper.insertAiGroupBalanceChangeRecord(aiGroupBalanceChangeRecord); aiGroupBalanceChangeRecord.setCreateTime(DateUtils.getNowDate());
return aiGroupBalanceChangeRecordMapper.insert(aiGroupBalanceChangeRecord);
} }
/**
* 修改团队部门余额变动
*
* @param aiGroupBalanceChangeRecord 团队部门余额变动
* @return 结果
*/
@Override @Override
public int updateAiGroupBalanceChangeRecord(AiGroupBalanceChangeRecord aiGroupBalanceChangeRecord) { public int updateAiGroupBalanceChangeRecord(AiGroupBalanceChangeRecord aiGroupBalanceChangeRecord) {
return aiGroupBalanceChangeRecordMapper.updateAiGroupBalanceChangeRecord(aiGroupBalanceChangeRecord); aiGroupBalanceChangeRecord.setUpdateTime(DateUtils.getNowDate());
return aiGroupBalanceChangeRecordMapper.updateById(aiGroupBalanceChangeRecord);
} }
/**
* 批量删除团队部门余额变动
*
* @param ids 需要删除的团队部门余额变动主键
* @return 结果
*/
@Override @Override
public int deleteAiGroupBalanceChangeRecordByIds(String[] ids) { public int deleteAiGroupBalanceChangeRecordByIds(String[] ids)
return aiGroupBalanceChangeRecordMapper.deleteAiGroupBalanceChangeRecordByIds(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; 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.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 @Service
public class AiVideoReportDataServiceImpl implements IAiVideoReportDataService { 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 @Autowired
private AiVideoReportDataMapper videoReportDataMapper; private AiVideoReportDataMapper aiVideoReportDataMapper;
/**
* 查询AI视频生成统计数据作为其他统计报的数据源
*
* @param id AI视频生成统计数据作为其他统计报的数据源主键
* @return AI视频生成统计数据作为其他统计报的数据源
*/
@Override @Override
public AiVideoReportData selectById(Long id) { public AiVideoReportData selectAiVideoReportDataById(String id) {
return videoReportDataMapper.selectById(id); return aiVideoReportDataMapper.selectById(id);
}
@Override
public int insert(AiVideoReportData entity) {
return videoReportDataMapper.insert(entity);
} }
/** /**
* 部门近七日汇总数据 * 查询AI视频生成统计数据作为其他统计报的数据源列表
*
* @param aiVideoReportData AI视频生成统计数据作为其他统计报的数据源
* @return AI视频生成统计数据作为其他统计报的数据源
*/ */
@Override @Override
@Cacheable(cacheNames = RedisKey.CACHE_DEPT_SUMMARY, key = "#deptId") public List<AiVideoReportData> selectAiVideoReportDataList(AiVideoReportData aiVideoReportData) {
public DeptSummaryDTO getSevenDayDeptSummaryData(Long deptId) { LambdaQueryWrapper<AiVideoReportData> query = Wrappers.lambdaQuery(aiVideoReportData);
Date endTime = new Date(); query.orderByDesc(AiVideoReportData::getId);
// 获取今天的0点再减去7天 return aiVideoReportDataMapper.selectList(query);
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);
} }
/**
* 分页查询AI视频生成统计数据作为其他统计报的数据源列表
*
* @param aiVideoReportData AI视频生成统计数据作为其他统计报的数据源
* @return AI视频生成统计数据作为其他统计报的数据源
*/
@Override @Override
public List<AiVideoReportData> selectTeamDailyConsumeByDeptId(String statDate, Long deptId) { public IPage<AiVideoReportData> selectAiVideoReportDataPage(Page page, AiVideoReportData aiVideoReportData) {
return videoReportDataMapper.selectTeamDailyConsumeByDeptId(statDate, deptId); LambdaQueryWrapper<AiVideoReportData> query = Wrappers.lambdaQuery(aiVideoReportData);
return aiVideoReportDataMapper.selectPage(page, query);
} }
/**
* 新增AI视频生成统计数据作为其他统计报的数据源
*
* @param aiVideoReportData AI视频生成统计数据作为其他统计报的数据源
* @return 结果
*/
@Override @Override
public void syncVideoConsumeIncrement(Date createTime, Long deptId, Long userId, BigDecimal score, Long useTokens) { public int insertAiVideoReportData(AiVideoReportData aiVideoReportData) {
if (createTime == null || deptId == null || userId == null) { aiVideoReportData.setCreateTime(DateUtils.getNowDate());
return; return aiVideoReportDataMapper.insert(aiVideoReportData);
} }
BigDecimal scoreSafe = score != null ? score : BigDecimal.ZERO;
Long useTokensSafe = useTokens != null ? useTokens : 0L; /**
videoReportDataMapper.upsertVideoConsumeIncrement( * 修改AI视频生成统计数据作为其他统计报的数据源
formatDateKey(createTime), *
deptId, * @param aiVideoReportData AI视频生成统计数据作为其他统计报的数据源
userId, * @return 结果
scoreSafe, */
1L, @Override
useTokensSafe); 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 @Override
public List<AiVideoReportData> selectTeamDailyConsumeList(String statDate, String deptName) { public List<AiVideoReportData> selectTeamDailyConsumeList(String statDate, String deptName) {
return videoReportDataMapper.selectTeamDailyConsumeList(statDate, deptName); return aiVideoReportDataMapper.selectTeamDailyConsumeList(statDate, deptName);
} }
@Override @Override
public List<AiVideoReportData> selectAiVideoReportDataList(AiVideoReportData aiVideoReportData) { public List<AiVideoReportData> selectTeamDailyConsumeByDeptId(String statDate, Long deptId) {
return videoReportDataMapper.selectAiVideoReportDataList(aiVideoReportData); return aiVideoReportDataMapper.selectTeamDailyConsumeByDeptId(statDate, deptId);
} }
@Override @Override
public AiVideoReportData selectAiVideoReportDataById(String id) { public void syncVideoConsumeIncrement(Date createTime, Long deptId, Long userId, BigDecimal score, Long useTokens) {
return videoReportDataMapper.selectAiVideoReportDataById(id); 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 @Override
public int insertAiVideoReportData(AiVideoReportData aiVideoReportData) { public void syncRechargeScoreIncrement(Date createTime, Long deptId, BigDecimal rechargeScore) {
return videoReportDataMapper.insertAiVideoReportData(aiVideoReportData); if (createTime == null || deptId == null || rechargeScore == null) {
return;
} }
String dateKey = new SimpleDateFormat("yyyyMMddHH").format(createTime);
@Override aiVideoReportDataMapper.upsertRechargeScoreIncrement(dateKey, deptId, rechargeScore);
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);
} }
} }

View File

@ -6,7 +6,6 @@ import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
import java.util.UUID; import java.util.UUID;
import com.ruoyi.common.constant.BalanceChangerConstants;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@ -118,6 +117,6 @@ public class DeptChargeRefundServiceImpl implements IDeptChargeRefundService {
private static String buildOrderNum() { private static String buildOrderNum() {
String uuid = UUID.randomUUID().toString().replace("-", "").substring(0, 8); String uuid = UUID.randomUUID().toString().replace("-", "").substring(0, 8);
String dateTime = new SimpleDateFormat("yyyyMMdd").format(new Date()); 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(); 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); int rows = deptService.addDeptBalance(deptId, amount);
if (rows == 0) { if (rows == 0) {
@ -86,7 +88,7 @@ public class DeptUserScoreTransferTxService {
} }
BigDecimal deptBalAfter = getDeptBalance(deptId); 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) { private AiUser requireUserWithDept(Long id) {
@ -142,6 +144,6 @@ public class DeptUserScoreTransferTxService {
private static String buildOrderNum() { private static String buildOrderNum() {
String uuid = UUID.randomUUID().toString().replace("-", "").substring(0, 8); String uuid = UUID.randomUUID().toString().replace("-", "").substring(0, 8);
String dateTime = new SimpleDateFormat("yyyyMMdd").format(new Date()); 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"/> <include refid="selectAiBalanceChangeRecordVo"/>
<where> <where>
and u.dept_id = #{deptId} and u.dept_id = #{deptId}
<if test="query.nickname != null and query.nickname != '' "> and u.nickname like concat('%', #{query.nickname}, '%') </if> <if test="q.nickname != null and q.nickname != '' "> and u.nickname like concat('%', #{q.nickname}, '%') </if>
<if test="query.userId != null "> and r.user_id = #{query.userId}</if> <if test="q.userId != null "> and r.user_id = #{q.userId}</if>
<if test="query.uuid != null "> and u.user_id = #{query.uuid}</if> <if test="q.uuid != null "> and u.user_id = #{q.uuid}</if>
<if test="query.type != null "> and r.type = #{query.type}</if> <if test="q.type != null "> and r.type = #{q.type}</if>
<if test="query.changeAmount != null "> and r.change_amount = #{query.changeAmount}</if> <if test="q.changeAmount != null "> and r.change_amount = #{q.changeAmount}</if>
<if test="query.resultAmount != null "> and r.result_amount = #{query.resultAmount}</if> <if test="q.resultAmount != null "> and r.result_amount = #{q.resultAmount}</if>
<if test="query.params.beginTime != null and query.params.beginTime != ''"> <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(#{query.params.beginTime},'%Y%m%d') AND date_format(r.create_time,'%Y%m%d') &gt;= date_format(#{q.params.beginTime},'%Y%m%d')
</if> </if>
<if test="query.params.endTime != null and query.params.endTime != ''"> <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(#{query.params.endTime},'%Y%m%d') AND date_format(r.create_time,'%Y%m%d') &lt;= date_format(#{q.params.endTime},'%Y%m%d')
</if> </if>
</where> </where>
order by r.id desc order by r.id desc

View File

@ -93,6 +93,3 @@ CREATE TABLE `ai_charge_refund_order` (
COMMENT='团队(部门)充值退款订单表' COMMENT='团队(部门)充值退款订单表'
COLLATE='utf8mb4_unicode_ci' COLLATE='utf8mb4_unicode_ci'
ENGINE=InnoDB; 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) 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, ''); 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`;