Merge branch 'seedance_balance' of https://gitea.06zk.com/best_yunwei/ai_images into seedance_balance
# Conflicts: # web-api/ruoyi-system/src/main/java/com/ruoyi/ai/mapper/AiVideoReportDataMapper.java
This commit is contained in:
commit
b2f1bc8439
|
|
@ -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'
|
||||
})
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
import request from '@/utils/request'
|
||||
|
||||
// 查询团队每日消耗统计
|
||||
export function listData(query) {
|
||||
return request({
|
||||
url: '/ai/data/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import request from '@/utils/request'
|
||||
|
||||
// 查询订单管理列表
|
||||
// 查询团队(部门)充值退款订单列表
|
||||
export function listOrder(query) {
|
||||
return request({
|
||||
url: '/ai/order/list',
|
||||
|
|
@ -9,7 +9,7 @@ export function listOrder(query) {
|
|||
})
|
||||
}
|
||||
|
||||
// 查询订单管理详细
|
||||
// 查询团队(部门)充值退款订单详细
|
||||
export function getOrder(id) {
|
||||
return request({
|
||||
url: '/ai/order/' + id,
|
||||
|
|
@ -17,7 +17,7 @@ export function getOrder(id) {
|
|||
})
|
||||
}
|
||||
|
||||
// 新增订单管理
|
||||
// 新增团队(部门)充值退款订单
|
||||
export function addOrder(data) {
|
||||
return request({
|
||||
url: '/ai/order',
|
||||
|
|
@ -26,7 +26,7 @@ export function addOrder(data) {
|
|||
})
|
||||
}
|
||||
|
||||
// 修改订单管理
|
||||
// 修改团队(部门)充值退款订单
|
||||
export function updateOrder(data) {
|
||||
return request({
|
||||
url: '/ai/order',
|
||||
|
|
@ -35,29 +35,10 @@ export function updateOrder(data) {
|
|||
})
|
||||
}
|
||||
|
||||
export function changeIsTop(id, isTop) {
|
||||
const data = {
|
||||
id,
|
||||
isTop
|
||||
}
|
||||
return request({
|
||||
url: '/ai/order',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除订单管理
|
||||
// 删除团队(部门)充值退款订单
|
||||
export function delOrder(id) {
|
||||
return request({
|
||||
url: '/ai/order/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function downloadVideo(id) {
|
||||
return request({
|
||||
url: '/api/ai/' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
})
|
||||
}
|
||||
|
|
@ -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' })
|
||||
}
|
||||
|
|
@ -0,0 +1,270 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
|
||||
<el-form-item label="部门ID" prop="deptId">
|
||||
<el-input
|
||||
v-model="queryParams.deptId"
|
||||
placeholder="请输入部门ID"
|
||||
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">
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
icon="el-icon-plus"
|
||||
size="mini"
|
||||
@click="handleAdd"
|
||||
v-hasPermi="['ai:config:add']"
|
||||
>新增</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="success"
|
||||
plain
|
||||
icon="el-icon-edit"
|
||||
size="mini"
|
||||
:disabled="single"
|
||||
@click="handleUpdate"
|
||||
v-hasPermi="['ai:config:edit']"
|
||||
>修改</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="danger"
|
||||
plain
|
||||
icon="el-icon-delete"
|
||||
size="mini"
|
||||
:disabled="multiple"
|
||||
@click="handleDelete"
|
||||
v-hasPermi="['ai:config:remove']"
|
||||
>删除</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="warning"
|
||||
plain
|
||||
icon="el-icon-download"
|
||||
size="mini"
|
||||
@click="handleExport"
|
||||
v-hasPermi="['ai:config:export']"
|
||||
>导出</el-button>
|
||||
</el-col>
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
<el-table v-loading="loading" :data="configList" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="ID" align="center" prop="id" />
|
||||
<el-table-column label="部门ID" align="center" prop="deptId" />
|
||||
<el-table-column label="视频模型列表JSON(label+value)" align="center" prop="modelParm" />
|
||||
<el-table-column label="Byte project,加密" align="center" prop="project" />
|
||||
<el-table-column label="Byte API Key,加密" align="center" prop="byteApiKey" />
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-edit"
|
||||
@click="handleUpdate(scope.row)"
|
||||
v-hasPermi="['ai:config:edit']"
|
||||
>修改</el-button>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-delete"
|
||||
@click="handleDelete(scope.row)"
|
||||
v-hasPermi="['ai:config:remove']"
|
||||
>删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
v-show="total>0"
|
||||
:total="total"
|
||||
:page.sync="queryParams.pageNum"
|
||||
:limit.sync="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
|
||||
<!-- 添加或修改团队(部门)对应火山引擎配置对话框 -->
|
||||
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
|
||||
<el-form-item label="部门ID" prop="deptId">
|
||||
<el-input v-model="form.deptId" placeholder="请输入部门ID" />
|
||||
</el-form-item>
|
||||
<el-form-item label="视频模型列表JSON(label+value)" prop="modelParm">
|
||||
<el-input v-model="form.modelParm" type="textarea" placeholder="请输入内容" />
|
||||
</el-form-item>
|
||||
<el-form-item label="Byte project,加密" prop="project">
|
||||
<el-input v-model="form.project" placeholder="请输入Byte project,加密" />
|
||||
</el-form-item>
|
||||
<el-form-item label="Byte API Key,加密" prop="byteApiKey">
|
||||
<el-input v-model="form.byteApiKey" placeholder="请输入Byte API Key,加密" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listConfig, getConfig, delConfig, addConfig, updateConfig } from "@/api/ai/config"
|
||||
|
||||
export default {
|
||||
name: "Config",
|
||||
data() {
|
||||
return {
|
||||
// 遮罩层
|
||||
loading: true,
|
||||
// 选中数组
|
||||
ids: [],
|
||||
// 非单个禁用
|
||||
single: true,
|
||||
// 非多个禁用
|
||||
multiple: true,
|
||||
// 显示搜索条件
|
||||
showSearch: true,
|
||||
// 总条数
|
||||
total: 0,
|
||||
// 团队(部门)对应火山引擎配置表格数据
|
||||
configList: [],
|
||||
// 弹出层标题
|
||||
title: "",
|
||||
// 是否显示弹出层
|
||||
open: false,
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
deptId: null,
|
||||
modelParm: null,
|
||||
project: null,
|
||||
byteApiKey: null,
|
||||
},
|
||||
// 表单参数
|
||||
form: {},
|
||||
// 表单校验
|
||||
rules: {
|
||||
deptId: [
|
||||
{ required: true, message: "部门ID不能为空", trigger: "blur" }
|
||||
],
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getList()
|
||||
},
|
||||
methods: {
|
||||
/** 查询团队(部门)对应火山引擎配置列表 */
|
||||
getList() {
|
||||
this.loading = true
|
||||
listConfig(this.queryParams).then(response => {
|
||||
this.configList = response.rows
|
||||
this.total = response.total
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
// 取消按钮
|
||||
cancel() {
|
||||
this.open = false
|
||||
this.reset()
|
||||
},
|
||||
// 表单重置
|
||||
reset() {
|
||||
this.form = {
|
||||
id: null,
|
||||
deptId: null,
|
||||
modelParm: null,
|
||||
project: null,
|
||||
byteApiKey: null,
|
||||
createBy: null,
|
||||
createTime: null,
|
||||
updateBy: null,
|
||||
updateTime: null
|
||||
}
|
||||
this.resetForm("form")
|
||||
},
|
||||
/** 搜索按钮操作 */
|
||||
handleQuery() {
|
||||
this.queryParams.pageNum = 1
|
||||
this.getList()
|
||||
},
|
||||
/** 重置按钮操作 */
|
||||
resetQuery() {
|
||||
this.resetForm("queryForm")
|
||||
this.handleQuery()
|
||||
},
|
||||
// 多选框选中数据
|
||||
handleSelectionChange(selection) {
|
||||
this.ids = selection.map(item => item.id)
|
||||
this.single = selection.length!==1
|
||||
this.multiple = !selection.length
|
||||
},
|
||||
/** 新增按钮操作 */
|
||||
handleAdd() {
|
||||
this.reset()
|
||||
this.open = true
|
||||
this.title = "添加团队(部门)对应火山引擎配置"
|
||||
},
|
||||
/** 修改按钮操作 */
|
||||
handleUpdate(row) {
|
||||
this.reset()
|
||||
const id = row.id || this.ids
|
||||
getConfig(id).then(response => {
|
||||
this.form = response.data
|
||||
this.open = true
|
||||
this.title = "修改团队(部门)对应火山引擎配置"
|
||||
})
|
||||
},
|
||||
/** 提交按钮 */
|
||||
submitForm() {
|
||||
this.$refs["form"].validate(valid => {
|
||||
if (valid) {
|
||||
if (this.form.id != null) {
|
||||
updateConfig(this.form).then(response => {
|
||||
this.$modal.msgSuccess("修改成功")
|
||||
this.open = false
|
||||
this.getList()
|
||||
})
|
||||
} else {
|
||||
addConfig(this.form).then(response => {
|
||||
this.$modal.msgSuccess("新增成功")
|
||||
this.open = false
|
||||
this.getList()
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
/** 删除按钮操作 */
|
||||
handleDelete(row) {
|
||||
const ids = row.id || this.ids
|
||||
this.$modal.confirm('是否确认删除团队(部门)对应火山引擎配置编号为"' + ids + '"的数据项?').then(function() {
|
||||
return delConfig(ids)
|
||||
}).then(() => {
|
||||
this.getList()
|
||||
this.$modal.msgSuccess("删除成功")
|
||||
}).catch(() => {})
|
||||
},
|
||||
/** 导出按钮操作 */
|
||||
handleExport() {
|
||||
this.download('ai/config/export', {
|
||||
...this.queryParams
|
||||
}, `config_${new Date().getTime()}.xlsx`)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,141 @@
|
|||
<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="deptId">
|
||||
<el-select
|
||||
v-model="queryParams.deptId"
|
||||
placeholder="请选择团队"
|
||||
clearable
|
||||
filterable
|
||||
style="width: 220px"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in deptOptions"
|
||||
:key="item.deptId"
|
||||
:label="item.deptName"
|
||||
:value="item.deptId"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<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"
|
||||
import { listDept } from "@/api/ai/dept"
|
||||
|
||||
export default {
|
||||
name: "TeamConsumeData",
|
||||
data() {
|
||||
return {
|
||||
// 遮罩层:首屏不自动查询,默认不展示加载状态
|
||||
loading: false,
|
||||
// 显示搜索条件
|
||||
showSearch: true,
|
||||
// 总条数
|
||||
total: 0,
|
||||
// 团队每日消耗统计表格数据
|
||||
dataList: [],
|
||||
// 团队下拉选项(仅二级部门)
|
||||
deptOptions: [],
|
||||
// 首次进入默认不查询
|
||||
searched: false,
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
statDate: null,
|
||||
deptId: null
|
||||
},
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadSecondLevelDeptOptions()
|
||||
},
|
||||
methods: {
|
||||
/** 加载二级部门选项 */
|
||||
loadSecondLevelDeptOptions() {
|
||||
listDept({ status: "0" }).then(response => {
|
||||
const allDeptList = response.data || []
|
||||
this.deptOptions = allDeptList.filter(item => this.isSecondLevelDept(item))
|
||||
})
|
||||
},
|
||||
/** 判断是否为二级部门(一级部门的直属子部门) */
|
||||
isSecondLevelDept(dept) {
|
||||
if (!dept || !dept.ancestors) {
|
||||
return false
|
||||
}
|
||||
return String(dept.ancestors).split(",").filter(Boolean).length === 2
|
||||
},
|
||||
/** 查询团队每日消耗统计列表 */
|
||||
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.deptId) {
|
||||
this.$modal.msgWarning("请先填写日期和团队名称后再搜索")
|
||||
return
|
||||
}
|
||||
this.searched = true
|
||||
this.queryParams.pageNum = 1
|
||||
this.getList()
|
||||
},
|
||||
/** 重置按钮操作 */
|
||||
resetQuery() {
|
||||
this.resetForm("queryForm")
|
||||
this.searched = false
|
||||
this.loading = false
|
||||
this.dataList = []
|
||||
this.total = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -1,79 +1,59 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
<el-form
|
||||
:model="queryParams"
|
||||
ref="queryForm"
|
||||
size="small"
|
||||
:inline="true"
|
||||
v-show="showSearch"
|
||||
label-width="68px"
|
||||
>
|
||||
<el-form-item label="订单编号" prop="orderNum">
|
||||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="88px">
|
||||
<el-form-item label="团队名称" prop="deptName">
|
||||
<el-input
|
||||
v-model="queryParams.orderNum"
|
||||
placeholder="请输入订单编号"
|
||||
v-model="queryParams.deptName"
|
||||
placeholder="支持模糊搜索"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="用户ID" prop="uuid">
|
||||
<el-input
|
||||
v-model="queryParams.uuid"
|
||||
placeholder="请输入用户ID"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="操作类型" prop="type">
|
||||
<el-select v-model="queryParams.type" placeholder="请选择操作类型" clearable>
|
||||
<el-option
|
||||
v-for="dict in dict.type.ai_function_type"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
:value="dict.value"
|
||||
/>
|
||||
<el-form-item label="类型" prop="orderType">
|
||||
<el-select v-model="queryParams.orderType" placeholder="全部" clearable style="width: 140px">
|
||||
<el-option v-for="item in orderTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否置顶" prop="isTop">
|
||||
<el-select v-model="queryParams.isTop" placeholder="请选择" clearable>
|
||||
<el-option
|
||||
v-for="dict in dict.type.sys_yes_no"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
:value="dict.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-select
|
||||
v-model="queryParams.status"
|
||||
placeholder="请选择状态"
|
||||
filterable
|
||||
clearable
|
||||
style="width: 200px; margin-bottom: 16px;"
|
||||
>
|
||||
<el-option
|
||||
v-for="(label, value) in statusMap"
|
||||
:key="value"
|
||||
:label="label"
|
||||
:value="Number(value)"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="创建时间">
|
||||
<el-date-picker
|
||||
v-model="dateRange"
|
||||
style="width: 240px"
|
||||
value-format="yyyy-MM-dd"
|
||||
type="daterange"
|
||||
range-separator="-"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
></el-date-picker>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
icon="el-icon-plus"
|
||||
size="mini"
|
||||
@click="handleAdd"
|
||||
v-hasPermi="['ai:order:add']"
|
||||
>新增</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="success"
|
||||
plain
|
||||
icon="el-icon-edit"
|
||||
size="mini"
|
||||
:disabled="single"
|
||||
@click="handleUpdate"
|
||||
v-hasPermi="['ai:order:edit']"
|
||||
>修改</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="danger"
|
||||
plain
|
||||
icon="el-icon-delete"
|
||||
size="mini"
|
||||
:disabled="multiple"
|
||||
@click="handleDelete"
|
||||
v-hasPermi="['ai:order:remove']"
|
||||
>删除</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="warning"
|
||||
plain
|
||||
|
|
@ -82,113 +62,45 @@
|
|||
@click="handleExport"
|
||||
v-hasPermi="['ai:order:export']"
|
||||
>导出</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-col>
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
<el-table v-loading="loading" :data="orderList" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="主键ID" align="center" prop="id" width="60" />
|
||||
<!-- <el-table-column label="备注" align="center" prop="remark" /> -->
|
||||
<el-table-column label="订单编号" align="center" prop="orderNum" width="150"/>
|
||||
<el-table-column label="用户ID" align="center" prop="uuid" width="100" />
|
||||
<el-table-column label="操作类型" align="center" prop="type" width="90" >
|
||||
<el-table-column label="ID" align="center" prop="id" width="72" />
|
||||
<el-table-column label="团队名称" align="center" prop="deptName" min-width="120" show-overflow-tooltip />
|
||||
<el-table-column label="类型" align="center" width="100">
|
||||
<template slot-scope="scope">
|
||||
<dict-tag :options="dict.type.ai_function_type" :value="scope.row.type" />
|
||||
<span>{{ orderTypeLabel(scope.row.orderType) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="金额" align="center" prop="amount" width="100" />
|
||||
<el-table-column label="生成结果" align="center" width="200">
|
||||
<el-table-column label="金额(元)" align="center" prop="money" width="100" />
|
||||
<el-table-column label="积分" align="center" prop="amount" width="100" />
|
||||
<el-table-column label="时间" align="center" prop="createTime" width="160">
|
||||
<template slot-scope="scope">
|
||||
<!-- 判断是否为链接 -->
|
||||
<template v-if="isUrl(scope.row.result)">
|
||||
<!-- 图片链接 -->
|
||||
<img
|
||||
v-if="isImage(scope.row.result)"
|
||||
:src="scope.row.result"
|
||||
class="preview-img"
|
||||
@click="viewImage(scope.row.result)"
|
||||
alt="预览图片"
|
||||
/>
|
||||
<!-- 视频链接 -->
|
||||
<video
|
||||
v-else-if="isVideo(scope.row.result)"
|
||||
:src="scope.row.result"
|
||||
class="preview-video"
|
||||
@click="playVideo(scope.row.result)"
|
||||
/>
|
||||
</template>
|
||||
<!-- 视频任务失败等场景:result 为 VideoTaskError JSON(表格内简短,悬停看全文) -->
|
||||
<template v-else-if="parseVolcTaskErrorJson(scope.row.result)">
|
||||
<span
|
||||
v-for="err in [parseVolcTaskErrorJson(scope.row.result)]"
|
||||
:key="'oe-' + scope.row.id"
|
||||
class="order-result-error-wrap"
|
||||
>
|
||||
<el-tooltip
|
||||
placement="top-start"
|
||||
effect="dark"
|
||||
:open-delay="200"
|
||||
popper-class="order-result-error-tooltip-popper"
|
||||
>
|
||||
<div slot="content" class="order-result-error-tooltip-body">
|
||||
<div class="order-result-error-tooltip-row">
|
||||
<span class="order-result-error-tooltip-k">错误编号:</span>
|
||||
<span class="order-result-error-tooltip-v">{{ err.code || '—' }}</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="volcTaskErrorHintForCode(err.code)"
|
||||
class="order-result-error-tooltip-row"
|
||||
>
|
||||
<span class="order-result-error-tooltip-k">中文说明:</span>
|
||||
<span class="order-result-error-tooltip-v">{{
|
||||
volcTaskErrorHintForCode(err.code)
|
||||
}}</span>
|
||||
</div>
|
||||
<div class="order-result-error-tooltip-row order-result-error-tooltip-row--msg">
|
||||
<span class="order-result-error-tooltip-k">信息:</span>
|
||||
<span class="order-result-error-tooltip-v">{{ err.message || '—' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<span class="order-result-error-compact">{{ volcTaskErrorCellSummary(err) }}</span>
|
||||
</el-tooltip>
|
||||
</span>
|
||||
</template>
|
||||
<!-- 非链接内容(如任务 id,可点击尝试拉取视频) -->
|
||||
<span v-else @click="handleOtherEvent(scope.row)">{{ scope.row.result }}</span>
|
||||
<span>{{ parseTime(scope.row.createTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="文字描述" align="center" prop="text">
|
||||
<el-table-column label="备注" align="center" prop="remark" min-width="140" show-overflow-tooltip />
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="140">
|
||||
<template slot-scope="scope">
|
||||
<!-- 核心:给 popover 加 ref,触发元素绑定 v-popover -->
|
||||
<el-popover
|
||||
ref="promptPopover"
|
||||
placement="top"
|
||||
width="400"
|
||||
trigger="hover"
|
||||
:content="scope.row.text || '无提示词'"
|
||||
></el-popover>
|
||||
<!-- 触发元素:绑定 v-popover 到 popover 的 ref -->
|
||||
<div
|
||||
class="text-ellipsis-two-lines"
|
||||
v-popover:promptPopover
|
||||
style="cursor: pointer;"
|
||||
>{{ scope.row.text}}</div>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-edit"
|
||||
@click="handleUpdate(scope.row)"
|
||||
v-hasPermi="['ai:order:edit']"
|
||||
>修改</el-button>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-delete"
|
||||
@click="handleDelete(scope.row)"
|
||||
v-hasPermi="['ai:order:remove']"
|
||||
>删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="置顶" align="center" key="status" width="60">
|
||||
<template slot-scope="scope">
|
||||
<el-switch
|
||||
v-model="scope.row.isTop"
|
||||
active-value="Y"
|
||||
inactive-value="N"
|
||||
@change="handleIsTopChange(scope.row)"
|
||||
></el-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="创建时间" align="center" prop="createTime" width="150"/>
|
||||
<el-table-column label="状态" align="center" prop="status" :formatter="formatStatus" width="70"/>
|
||||
<el-table-column label="来源" align="center" prop="source" width="70"/>
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
|
|
@ -199,39 +111,40 @@
|
|||
@pagination="getList"
|
||||
/>
|
||||
|
||||
<!-- 添加或修改订单管理对话框 -->
|
||||
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
|
||||
<el-form-item label="订单编号" prop="orderNum">
|
||||
<el-input v-model="form.orderNum" placeholder="请输入订单编号" />
|
||||
<el-dialog :title="title" :visible.sync="open" width="560px" append-to-body>
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
|
||||
<el-form-item label="团队" prop="deptId">
|
||||
<treeselect
|
||||
v-model="form.deptId"
|
||||
:options="deptOptions"
|
||||
:normalizer="normalizer"
|
||||
:show-count="true"
|
||||
placeholder="请选择团队(二级部门)"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="用户ID" prop="userId">
|
||||
<el-input v-model="form.userId" placeholder="请输入用户ID" />
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-select
|
||||
v-model="form.status"
|
||||
placeholder="请选择状态"
|
||||
filterable
|
||||
clearable
|
||||
style="width: 200px;"
|
||||
>
|
||||
<el-option
|
||||
v-for="(label, value) in statusMap"
|
||||
:key="value"
|
||||
:label="label"
|
||||
:value="Number(value)"
|
||||
/>
|
||||
<el-form-item label="类型" prop="orderType">
|
||||
<el-select v-model="form.orderType" placeholder="请选择" style="width: 100%">
|
||||
<el-option v-for="item in orderTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="金额" prop="amount">
|
||||
<el-input v-model="form.amount" placeholder="请输入金额" />
|
||||
<el-form-item label="金额(元)" prop="money">
|
||||
<el-input v-model="form.money" placeholder="可选,对账用金额" />
|
||||
</el-form-item>
|
||||
<el-form-item label="生成结果" prop="result">
|
||||
<el-input v-model="form.result" placeholder="请输入生成结果" />
|
||||
<el-form-item label="积分" prop="amount">
|
||||
<el-input v-model="form.amount" placeholder="充值/退款填正数;手动修改可填负数表示扣减" />
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-select v-model="form.status" placeholder="请选择" style="width: 100%">
|
||||
<el-option label="进行中" :value="0" />
|
||||
<el-option label="已完成" :value="1" />
|
||||
<el-option label="失败" :value="2" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="订单编号" prop="orderNum" v-if="form.id != null">
|
||||
<el-input v-model="form.orderNum" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
|
||||
<el-input v-model="form.remark" type="textarea" :rows="3" placeholder="对账说明、打款信息等" maxlength="500" show-word-limit />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
|
|
@ -239,424 +152,158 @@
|
|||
<el-button @click="cancel">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 图片预览弹窗 -->
|
||||
<el-dialog :visible.sync="imageDialogVisible" title="图片预览" width="60%">
|
||||
<img :src="previewImageUrl" class="dialog-img" alt="大图预览" />
|
||||
</el-dialog>
|
||||
|
||||
<!-- 新增视频弹窗 -->
|
||||
<el-dialog :visible.sync="videoDialogVisible" title="视频播放" width="60%">
|
||||
<video :src="previewVideoUrl" controls class="dialog-video"></video>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
listOrder,
|
||||
getOrder,
|
||||
delOrder,
|
||||
addOrder,
|
||||
downloadVideo,
|
||||
changeIsTop,
|
||||
updateOrder
|
||||
} from "@/api/ai/order";
|
||||
import { listOrder, getOrder, delOrder, addOrder, updateOrder } from "@/api/ai/order"
|
||||
import { deptTreeSelect } from "@/api/system/user"
|
||||
import Treeselect from "@riophae/vue-treeselect"
|
||||
import "@riophae/vue-treeselect/dist/vue-treeselect.css"
|
||||
|
||||
export default {
|
||||
name: "Order",
|
||||
dicts: ["ai_function_type", "sys_yes_no"],
|
||||
name: "TeamChargeOrder",
|
||||
components: { Treeselect },
|
||||
data() {
|
||||
return {
|
||||
imageDialogVisible: false,
|
||||
videoDialogVisible: false,
|
||||
previewVideoUrl: "",
|
||||
previewImageUrl: "",
|
||||
dateRange: [],
|
||||
statusMap: {
|
||||
0: "进行中",
|
||||
1: "已完成",
|
||||
2: "已失败"
|
||||
},
|
||||
// 遮罩层
|
||||
loading: true,
|
||||
// 选中数组
|
||||
ids: [],
|
||||
// 非单个禁用
|
||||
single: true,
|
||||
// 非多个禁用
|
||||
multiple: true,
|
||||
// 显示搜索条件
|
||||
showSearch: true,
|
||||
// 总条数
|
||||
total: 0,
|
||||
// 订单管理表格数据
|
||||
orderList: [],
|
||||
// 弹出层标题
|
||||
title: "",
|
||||
// 是否显示弹出层
|
||||
open: false,
|
||||
// 查询参数
|
||||
deptOptions: [],
|
||||
orderTypeOptions: [
|
||||
{ label: "充值", value: 0 },
|
||||
{ label: "退款", value: 1 },
|
||||
{ label: "手动修改", value: 2 }
|
||||
],
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
orderNum: null,
|
||||
userId: null,
|
||||
type: null,
|
||||
amount: null,
|
||||
result: null,
|
||||
status: null
|
||||
deptName: null,
|
||||
orderType: null
|
||||
},
|
||||
// 表单参数
|
||||
form: {},
|
||||
// 表单校验
|
||||
rules: {
|
||||
delFlag: [
|
||||
{ required: true, message: "删除标志不能为空", trigger: "blur" }
|
||||
]
|
||||
deptId: [{ required: true, message: "请选择团队", trigger: "change" }],
|
||||
orderType: [{ required: true, message: "请选择类型", trigger: "change" }],
|
||||
amount: [{ required: true, message: "请填写积分", trigger: "blur" }],
|
||||
status: [{ required: true, message: "请选择状态", trigger: "change" }]
|
||||
}
|
||||
};
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getList();
|
||||
this.getDeptTree()
|
||||
this.getList()
|
||||
},
|
||||
methods: {
|
||||
handleIsTopChange(row) {
|
||||
let text = row.isTop === "Y" ? "置顶" : "取消置顶";
|
||||
this.$modal
|
||||
.confirm('确认要"' + text + '""' + row.id + '"作品吗?')
|
||||
.then(function() {
|
||||
return changeIsTop(row.id, row.isTop);
|
||||
})
|
||||
.then(() => {
|
||||
this.$modal.msgSuccess(text + "成功");
|
||||
})
|
||||
.catch(function() {
|
||||
row.isTop = row.isTop === "Y" ? "N" : "Y";
|
||||
});
|
||||
orderTypeLabel(orderType) {
|
||||
const n = orderType !== undefined && orderType !== null ? Number(orderType) : null
|
||||
const hit = this.orderTypeOptions.find(o => o.value === n)
|
||||
return hit ? hit.label : "—"
|
||||
},
|
||||
// 判断是否为 http(s) URL(与 portal-ui 生成视频模块一致)
|
||||
isUrl(str) {
|
||||
const value = String(str || "").trim();
|
||||
return /^https?:\/\//i.test(value);
|
||||
getDeptTree() {
|
||||
deptTreeSelect().then(response => {
|
||||
this.deptOptions = response.data || []
|
||||
})
|
||||
},
|
||||
/** 已知错误码对应中文说明(与门户 VideoGen 一致) */
|
||||
volcTaskErrorHintForCode(code) {
|
||||
const c = String(code || "").trim();
|
||||
const hints = {
|
||||
OutputVideoSensitiveContentDetected: "输出视频可能包含敏感信息",
|
||||
InvalidParameter: "请求参数无效"
|
||||
};
|
||||
return hints[c] || "";
|
||||
},
|
||||
/** 表格内摘要:已知码只显示中文,未知码显示 code */
|
||||
volcTaskErrorCellSummary(err) {
|
||||
if (!err) return "—";
|
||||
const code = String(err.code || "").trim();
|
||||
const hint = this.volcTaskErrorHintForCode(code);
|
||||
if (hint) return hint;
|
||||
if (code) return code;
|
||||
const msg = String(err.message || "").trim();
|
||||
return msg ? msg.slice(0, 32) + (msg.length > 32 ? "…" : "") : "—";
|
||||
},
|
||||
/** 已知火山错误码后附中文说明(括号),导出等场景可用 */
|
||||
volcFailureCodeWithHint(code) {
|
||||
const c = String(code || "").trim();
|
||||
if (!c) return "";
|
||||
const hint = this.volcTaskErrorHintForCode(c);
|
||||
return hint ? `${c}(${hint})` : c;
|
||||
},
|
||||
/** result 为火山回调失败写入的 VideoTaskError JSON 时解析为 { code, message } */
|
||||
parseVolcTaskErrorJson(str) {
|
||||
const s = String(str || "").trim();
|
||||
if (!s || s[0] !== "{") return null;
|
||||
try {
|
||||
const o = JSON.parse(s);
|
||||
if (
|
||||
o &&
|
||||
typeof o === "object" &&
|
||||
!Array.isArray(o) &&
|
||||
("code" in o || "message" in o)
|
||||
) {
|
||||
return {
|
||||
code: o.code != null ? String(o.code) : "",
|
||||
message: o.message != null ? String(o.message) : ""
|
||||
};
|
||||
}
|
||||
} catch (_) {
|
||||
/* ignore */
|
||||
normalizer(node) {
|
||||
if (node.children && !node.children.length) {
|
||||
delete node.children
|
||||
}
|
||||
return null;
|
||||
},
|
||||
// 判断是否为图片结果(与 portal-ui GeneratedAssets 一致)
|
||||
isImage(url) {
|
||||
const value = String(url || "").trim();
|
||||
if (!value) return false;
|
||||
return /\.(jpeg|jpg|png|gif|webp|bmp)(\?.*)?$/i.test(value);
|
||||
},
|
||||
// 判断是否为视频结果(与 portal-ui VideoGen/GeneratedAssets 一致)
|
||||
isVideo(url) {
|
||||
const value = String(url || "").trim();
|
||||
if (!value) return false;
|
||||
return /\.(mp4|mov|webm|ogg|m4v|avi|mkv)(\?.*)?$/i.test(value);
|
||||
},
|
||||
// 查看图片
|
||||
viewImage(url) {
|
||||
this.previewImageUrl = url;
|
||||
this.imageDialogVisible = true;
|
||||
},
|
||||
// 播放视频
|
||||
playVideo(url) {
|
||||
this.previewVideoUrl = url;
|
||||
this.videoDialogVisible = true;
|
||||
},
|
||||
// 非链接内容点击事件
|
||||
async handleOtherEvent(row) {
|
||||
if (this.parseVolcTaskErrorJson(row.result)) return;
|
||||
// 防止重复点击
|
||||
if (row.isDownloading) return;
|
||||
const originalResult = row.result;
|
||||
try {
|
||||
// 标记为下载中状态
|
||||
row.isDownloading = true;
|
||||
// 保存原始内容
|
||||
|
||||
// 修改显示内容为“下载中...”
|
||||
row.result = "下载中...";
|
||||
|
||||
// 执行下载操作
|
||||
const resultId = originalResult; // 假设result存储的是ID
|
||||
var res = await downloadVideo(resultId);
|
||||
if (res.status === "succeeded") {
|
||||
row.result = res.content.video_url;
|
||||
} else {
|
||||
row.result = "视频生成中"
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('下载失败:', error);
|
||||
// 失败后恢复原始内容
|
||||
row.result = originalResult || row.result.replace("下载中...", "");
|
||||
this.$message.error('下载失败,请重试');
|
||||
} finally {
|
||||
// 重置下载状态
|
||||
row.isDownloading = false;
|
||||
return {
|
||||
id: node.id,
|
||||
label: node.label,
|
||||
children: node.children
|
||||
}
|
||||
},
|
||||
|
||||
formatStatus(row) {
|
||||
// 如果有匹配的类型则显示对应文字,否则显示"未知"
|
||||
return this.statusMap[row.status] || "未知";
|
||||
},
|
||||
/** 查询订单管理列表 */
|
||||
getList() {
|
||||
this.loading = true;
|
||||
listOrder(this.addDateRange(this.queryParams, this.dateRange)).then(
|
||||
response => {
|
||||
this.orderList = response.rows;
|
||||
this.total = response.total;
|
||||
this.loading = false;
|
||||
}
|
||||
);
|
||||
this.loading = true
|
||||
listOrder(this.queryParams).then(response => {
|
||||
this.orderList = response.rows
|
||||
this.total = response.total
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
// 取消按钮
|
||||
cancel() {
|
||||
this.open = false;
|
||||
this.reset();
|
||||
this.open = false
|
||||
this.reset()
|
||||
},
|
||||
// 表单重置
|
||||
reset() {
|
||||
this.form = {
|
||||
id: null,
|
||||
delFlag: null,
|
||||
createBy: null,
|
||||
createTime: null,
|
||||
updateBy: null,
|
||||
updateTime: null,
|
||||
remark: null,
|
||||
orderNum: null,
|
||||
userId: null,
|
||||
type: null,
|
||||
amount: null,
|
||||
result: null,
|
||||
status: null
|
||||
};
|
||||
this.resetForm("form");
|
||||
deptId: undefined,
|
||||
orderType: 0,
|
||||
money: undefined,
|
||||
amount: undefined,
|
||||
remark: undefined,
|
||||
status: 1,
|
||||
orderNum: undefined
|
||||
}
|
||||
this.resetForm("form")
|
||||
},
|
||||
/** 搜索按钮操作 */
|
||||
handleQuery() {
|
||||
this.queryParams.pageNum = 1;
|
||||
this.getList();
|
||||
this.queryParams.pageNum = 1
|
||||
this.getList()
|
||||
},
|
||||
/** 重置按钮操作 */
|
||||
resetQuery() {
|
||||
this.dateRange = [];
|
||||
this.resetForm("queryForm");
|
||||
this.handleQuery();
|
||||
this.resetForm("queryForm")
|
||||
this.handleQuery()
|
||||
},
|
||||
// 多选框选中数据
|
||||
handleSelectionChange(selection) {
|
||||
this.ids = selection.map(item => item.id);
|
||||
this.single = selection.length !== 1;
|
||||
this.multiple = !selection.length;
|
||||
this.ids = selection.map(item => item.id)
|
||||
this.single = selection.length !== 1
|
||||
this.multiple = !selection.length
|
||||
},
|
||||
/** 新增按钮操作 */
|
||||
handleAdd() {
|
||||
this.reset();
|
||||
this.open = true;
|
||||
this.title = "添加订单管理";
|
||||
this.reset()
|
||||
this.open = true
|
||||
this.title = "新增团队订单"
|
||||
},
|
||||
/** 修改按钮操作 */
|
||||
handleUpdate(row) {
|
||||
this.reset();
|
||||
const id = row.id || this.ids;
|
||||
this.reset()
|
||||
const id = row.id || this.ids[0]
|
||||
getOrder(id).then(response => {
|
||||
this.form = response.data;
|
||||
this.open = true;
|
||||
this.title = "修改订单管理";
|
||||
});
|
||||
this.form = response.data
|
||||
this.open = true
|
||||
this.title = "修改团队订单"
|
||||
})
|
||||
},
|
||||
/** 提交按钮 */
|
||||
submitForm() {
|
||||
this.$refs["form"].validate(valid => {
|
||||
if (valid) {
|
||||
if (this.form.id != null) {
|
||||
updateOrder(this.form).then(response => {
|
||||
this.$modal.msgSuccess("修改成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
});
|
||||
} else {
|
||||
addOrder(this.form).then(response => {
|
||||
this.$modal.msgSuccess("新增成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
});
|
||||
}
|
||||
if (!valid) {
|
||||
return
|
||||
}
|
||||
});
|
||||
const payload = { ...this.form }
|
||||
if (payload.id == null) {
|
||||
addOrder(payload).then(() => {
|
||||
this.$modal.msgSuccess("新增成功")
|
||||
this.open = false
|
||||
this.getList()
|
||||
})
|
||||
} else {
|
||||
updateOrder(payload).then(() => {
|
||||
this.$modal.msgSuccess("修改成功")
|
||||
this.open = false
|
||||
this.getList()
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
/** 删除按钮操作 */
|
||||
handleDelete(row) {
|
||||
const ids = row.id || this.ids;
|
||||
this.$modal
|
||||
.confirm('是否确认删除订单管理编号为"' + ids + '"的数据项?')
|
||||
.then(function() {
|
||||
return delOrder(ids);
|
||||
})
|
||||
.then(() => {
|
||||
this.getList();
|
||||
this.$modal.msgSuccess("删除成功");
|
||||
})
|
||||
.catch(() => {});
|
||||
const ids = row.id || this.ids
|
||||
this.$modal.confirm("是否确认删除所选团队订单?").then(() => delOrder(ids)).then(() => {
|
||||
this.getList()
|
||||
this.$modal.msgSuccess("删除成功")
|
||||
}).catch(() => {})
|
||||
},
|
||||
/** 导出按钮操作 */
|
||||
handleExport() {
|
||||
this.download(
|
||||
"ai/order/export",
|
||||
{
|
||||
...this.queryParams
|
||||
},
|
||||
`order_${new Date().getTime()}.xlsx`
|
||||
);
|
||||
this.download("ai/order/export", { ...this.queryParams }, `team_orders_${new Date().getTime()}.xlsx`)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.dialog-video {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.preview-img {
|
||||
width: 80px;
|
||||
height: 60px;
|
||||
object-fit: cover;
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.preview-video {
|
||||
width: 120px;
|
||||
height: 80px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.dialog-img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.order-result-error-wrap {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.order-result-error-compact {
|
||||
display: inline-block;
|
||||
max-width: 200px;
|
||||
margin: 0 auto;
|
||||
font-size: 12px;
|
||||
line-height: 1.35;
|
||||
color: #c45656;
|
||||
cursor: help;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.order-result-error-tooltip-body {
|
||||
max-width: 420px;
|
||||
text-align: left;
|
||||
line-height: 1.5;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.order-result-error-tooltip-row {
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.order-result-error-tooltip-row:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.order-result-error-tooltip-row--msg .order-result-error-tooltip-v {
|
||||
display: block;
|
||||
margin-top: 2px;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.order-result-error-tooltip-k {
|
||||
font-weight: 600;
|
||||
color: #fde2e2;
|
||||
}
|
||||
|
||||
.order-result-error-tooltip-v {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.text-ellipsis-two-lines {
|
||||
/* 必须设置宽度(继承表格列宽,也可手动指定) */
|
||||
width: 100%;
|
||||
/* 核心属性:多行文本溢出隐藏 */
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2; /* 显示2行 */
|
||||
line-clamp: 2; /* 标准属性,兼容现代浏览器 */
|
||||
overflow: hidden;
|
||||
/* 可选:调整行高,优化显示 */
|
||||
line-height: 1.5;
|
||||
max-height: 3em; /* 行高1.5 × 2行 = 3em,防止高度溢出 */
|
||||
/* 可选:文本对齐 */
|
||||
text-align: center;
|
||||
/* 解决scoped样式穿透(如果需要) */
|
||||
/deep/ & {
|
||||
box-sizing: border-box;
|
||||
padding: 0 4px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,312 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
|
||||
<el-form-item label="订单号" prop="relationOrderNo">
|
||||
<el-input
|
||||
v-model="queryParams.relationOrderNo"
|
||||
placeholder="请输入关联(充值/退款)订单号"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="部门ID" prop="deptId">
|
||||
<el-input
|
||||
v-model="queryParams.deptId"
|
||||
placeholder="请输入部门ID"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="变更金额" prop="changeAmount">
|
||||
<el-input
|
||||
v-model="queryParams.changeAmount"
|
||||
placeholder="请输入变更金额"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="变更后金额" prop="resultAmount">
|
||||
<el-input
|
||||
v-model="queryParams.resultAmount"
|
||||
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">
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
icon="el-icon-plus"
|
||||
size="mini"
|
||||
@click="handleAdd"
|
||||
v-hasPermi="['ai:record:add']"
|
||||
>新增</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="success"
|
||||
plain
|
||||
icon="el-icon-edit"
|
||||
size="mini"
|
||||
:disabled="single"
|
||||
@click="handleUpdate"
|
||||
v-hasPermi="['ai:record:edit']"
|
||||
>修改</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="danger"
|
||||
plain
|
||||
icon="el-icon-delete"
|
||||
size="mini"
|
||||
:disabled="multiple"
|
||||
@click="handleDelete"
|
||||
v-hasPermi="['ai:record:remove']"
|
||||
>删除</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="warning"
|
||||
plain
|
||||
icon="el-icon-download"
|
||||
size="mini"
|
||||
@click="handleExport"
|
||||
v-hasPermi="['ai:record:export']"
|
||||
>导出</el-button>
|
||||
</el-col>
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
<el-table v-loading="loading" :data="recordList" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="ID" align="center" prop="id" />
|
||||
<el-table-column label="订单号" align="center" prop="relationOrderNo" />
|
||||
<el-table-column label="部门ID" align="center" prop="deptId" />
|
||||
<el-table-column label="操作类型" align="center" prop="type" />
|
||||
<el-table-column label="变更金额" align="center" prop="changeAmount" />
|
||||
<el-table-column label="变更后金额" align="center" prop="resultAmount" />
|
||||
<el-table-column label="备注" align="center" prop="remark" />
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-edit"
|
||||
@click="handleUpdate(scope.row)"
|
||||
v-hasPermi="['ai:record:edit']"
|
||||
>修改</el-button>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-delete"
|
||||
@click="handleDelete(scope.row)"
|
||||
v-hasPermi="['ai:record:remove']"
|
||||
>删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
v-show="total>0"
|
||||
:total="total"
|
||||
:page.sync="queryParams.pageNum"
|
||||
:limit.sync="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
|
||||
<!-- 添加或修改团队(部门)余额变动对话框 -->
|
||||
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
|
||||
<el-form-item label="订单号" prop="relationOrderNo">
|
||||
<el-input v-model="form.relationOrderNo" placeholder="请输入关联(充值/退款)订单号" />
|
||||
</el-form-item>
|
||||
<el-form-item label="部门ID" prop="deptId">
|
||||
<el-input v-model="form.deptId" placeholder="请输入部门ID" />
|
||||
</el-form-item>
|
||||
<el-form-item label="变更金额" prop="changeAmount">
|
||||
<el-input v-model="form.changeAmount" placeholder="请输入变更金额" />
|
||||
</el-form-item>
|
||||
<el-form-item label="变更后金额" prop="resultAmount">
|
||||
<el-input v-model="form.resultAmount" placeholder="请输入变更后金额" />
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="form.remark" placeholder="请输入备注" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listRecord, getRecord, delRecord, addRecord, updateRecord } from "@/api/ai/record"
|
||||
|
||||
export default {
|
||||
name: "Record",
|
||||
data() {
|
||||
return {
|
||||
// 遮罩层
|
||||
loading: true,
|
||||
// 选中数组
|
||||
ids: [],
|
||||
// 非单个禁用
|
||||
single: true,
|
||||
// 非多个禁用
|
||||
multiple: true,
|
||||
// 显示搜索条件
|
||||
showSearch: true,
|
||||
// 总条数
|
||||
total: 0,
|
||||
// 团队(部门)余额变动表格数据
|
||||
recordList: [],
|
||||
// 弹出层标题
|
||||
title: "",
|
||||
// 是否显示弹出层
|
||||
open: false,
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
relationOrderNo: null,
|
||||
deptId: null,
|
||||
type: null,
|
||||
changeAmount: null,
|
||||
resultAmount: null,
|
||||
},
|
||||
// 表单参数
|
||||
form: {},
|
||||
// 表单校验
|
||||
rules: {
|
||||
deptId: [
|
||||
{ required: true, message: "部门ID不能为空", trigger: "blur" }
|
||||
],
|
||||
type: [
|
||||
{ required: true, message: "操作类型不能为空", trigger: "change" }
|
||||
],
|
||||
changeAmount: [
|
||||
{ required: true, message: "变更金额不能为空", trigger: "blur" }
|
||||
],
|
||||
resultAmount: [
|
||||
{ required: true, message: "变更后金额不能为空", trigger: "blur" }
|
||||
],
|
||||
createTime: [
|
||||
{ required: true, message: "创建时间不能为空", trigger: "blur" }
|
||||
],
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getList()
|
||||
},
|
||||
methods: {
|
||||
/** 查询团队(部门)余额变动列表 */
|
||||
getList() {
|
||||
this.loading = true
|
||||
listRecord(this.queryParams).then(response => {
|
||||
this.recordList = response.rows
|
||||
this.total = response.total
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
// 取消按钮
|
||||
cancel() {
|
||||
this.open = false
|
||||
this.reset()
|
||||
},
|
||||
// 表单重置
|
||||
reset() {
|
||||
this.form = {
|
||||
id: null,
|
||||
relationOrderNo: null,
|
||||
deptId: null,
|
||||
type: null,
|
||||
changeAmount: null,
|
||||
resultAmount: null,
|
||||
remark: null,
|
||||
createTime: null,
|
||||
updateTime: null
|
||||
}
|
||||
this.resetForm("form")
|
||||
},
|
||||
/** 搜索按钮操作 */
|
||||
handleQuery() {
|
||||
this.queryParams.pageNum = 1
|
||||
this.getList()
|
||||
},
|
||||
/** 重置按钮操作 */
|
||||
resetQuery() {
|
||||
this.resetForm("queryForm")
|
||||
this.handleQuery()
|
||||
},
|
||||
// 多选框选中数据
|
||||
handleSelectionChange(selection) {
|
||||
this.ids = selection.map(item => item.id)
|
||||
this.single = selection.length!==1
|
||||
this.multiple = !selection.length
|
||||
},
|
||||
/** 新增按钮操作 */
|
||||
handleAdd() {
|
||||
this.reset()
|
||||
this.open = true
|
||||
this.title = "添加团队(部门)余额变动"
|
||||
},
|
||||
/** 修改按钮操作 */
|
||||
handleUpdate(row) {
|
||||
this.reset()
|
||||
const id = row.id || this.ids
|
||||
getRecord(id).then(response => {
|
||||
this.form = response.data
|
||||
this.open = true
|
||||
this.title = "修改团队(部门)余额变动"
|
||||
})
|
||||
},
|
||||
/** 提交按钮 */
|
||||
submitForm() {
|
||||
this.$refs["form"].validate(valid => {
|
||||
if (valid) {
|
||||
if (this.form.id != null) {
|
||||
updateRecord(this.form).then(response => {
|
||||
this.$modal.msgSuccess("修改成功")
|
||||
this.open = false
|
||||
this.getList()
|
||||
})
|
||||
} else {
|
||||
addRecord(this.form).then(response => {
|
||||
this.$modal.msgSuccess("新增成功")
|
||||
this.open = false
|
||||
this.getList()
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
/** 删除按钮操作 */
|
||||
handleDelete(row) {
|
||||
const ids = row.id || this.ids
|
||||
this.$modal.confirm('是否确认删除团队(部门)余额变动编号为"' + ids + '"的数据项?').then(function() {
|
||||
return delRecord(ids)
|
||||
}).then(() => {
|
||||
this.getList()
|
||||
this.$modal.msgSuccess("删除成功")
|
||||
}).catch(() => {})
|
||||
},
|
||||
/** 导出按钮操作 */
|
||||
handleExport() {
|
||||
this.download('ai/record/export', {
|
||||
...this.queryParams
|
||||
}, `record_${new Date().getTime()}.xlsx`)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
<el-form v-show="showSearch" ref="queryForm" :model="queryParams" size="small" :inline="true" label-width="88px">
|
||||
<el-form-item label="类型" prop="orderType">
|
||||
<el-select v-model="queryParams.orderType" clearable placeholder="全部">
|
||||
<el-option label="充值" :value="0" /><el-option label="退款" :value="1" /><el-option label="手动修改" :value="2" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="订单编号" prop="orderNum">
|
||||
<el-input v-model="queryParams.orderNum" 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 class="mb8"><right-toolbar :show-search.sync="showSearch" @queryTable="getList" /></el-row>
|
||||
<el-table v-loading="loading" :data="list">
|
||||
<el-table-column label="ID" prop="id" width="70" />
|
||||
<el-table-column label="团队" prop="deptName" min-width="100" show-overflow-tooltip />
|
||||
<el-table-column label="类型" width="90">
|
||||
<template slot-scope="s">{{ typeLabel(s.row.orderType) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="金额" prop="money" width="90" />
|
||||
<el-table-column label="积分" prop="amount" width="90" />
|
||||
<el-table-column label="时间" width="160"><template slot-scope="s">{{ parseTime(s.row.createTime) }}</template></el-table-column>
|
||||
<el-table-column label="备注" prop="remark" min-width="120" show-overflow-tooltip />
|
||||
</el-table>
|
||||
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listSubteamChargeOrder } from '@/api/subteam'
|
||||
export default {
|
||||
name: 'SubteamChargeOrder',
|
||||
data() {
|
||||
return {
|
||||
loading: true,
|
||||
showSearch: true,
|
||||
list: [],
|
||||
total: 0,
|
||||
queryParams: { pageNum: 1, pageSize: 10, orderType: undefined, orderNum: undefined }
|
||||
}
|
||||
},
|
||||
created() { this.getList() },
|
||||
methods: {
|
||||
typeLabel(t) {
|
||||
const m = { 0: '充值', 1: '退款', 2: '手动修改' }
|
||||
return m[t] != null ? m[t] : '—'
|
||||
},
|
||||
getList() {
|
||||
this.loading = true
|
||||
listSubteamChargeOrder(this.queryParams).then(res => {
|
||||
this.list = res.rows
|
||||
this.total = res.total
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
handleQuery() { this.queryParams.pageNum = 1; this.getList() },
|
||||
resetQuery() { this.resetForm('queryForm'); this.handleQuery() }
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
<el-form ref="queryForm" :model="queryParams" size="small" :inline="true" 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>
|
||||
<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>
|
||||
<p class="tip">仅展示当前团队数据;请选择日期后查询。</p>
|
||||
<el-table v-loading="loading" :data="list">
|
||||
<el-table-column label="日期" prop="dateKey" />
|
||||
<el-table-column label="团队" prop="deptName" />
|
||||
<el-table-column label="充值积分" prop="rechargeScore" />
|
||||
<el-table-column label="消耗积分" prop="score" />
|
||||
<el-table-column label="成功订单" prop="orderCount" />
|
||||
<el-table-column label="Tokens" 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 { listSubteamConsumeStat } from '@/api/subteam'
|
||||
export default {
|
||||
name: 'SubteamConsumeStat',
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
list: [],
|
||||
total: 0,
|
||||
queryParams: { pageNum: 1, pageSize: 10, statDate: null }
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getList() {
|
||||
if (!this.queryParams.statDate) {
|
||||
this.list = []
|
||||
this.total = 0
|
||||
return
|
||||
}
|
||||
this.loading = true
|
||||
listSubteamConsumeStat(this.queryParams).then(res => {
|
||||
this.list = res.rows
|
||||
this.total = res.total
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
handleQuery() {
|
||||
this.queryParams.pageNum = 1
|
||||
this.getList()
|
||||
},
|
||||
resetQuery() {
|
||||
this.resetForm('queryForm')
|
||||
this.list = []
|
||||
this.total = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.tip { color: #909399; font-size: 13px; margin-bottom: 12px; }
|
||||
</style>
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
<el-form v-show="showSearch" ref="queryForm" :model="queryParams" size="small" :inline="true">
|
||||
<el-form-item label="类型" prop="type">
|
||||
<el-input v-model="queryParams.type" clearable placeholder="0-4" @keyup.enter.native="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="关联单号" prop="relationOrderNo">
|
||||
<el-input v-model="queryParams.relationOrderNo" 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 class="mb8"><right-toolbar :show-search.sync="showSearch" @queryTable="getList" /></el-row>
|
||||
<el-table v-loading="loading" :data="list">
|
||||
<el-table-column label="ID" prop="id" width="80" />
|
||||
<el-table-column label="关联单号" prop="relationOrderNo" min-width="120" show-overflow-tooltip />
|
||||
<el-table-column label="类型" prop="type" width="80" />
|
||||
<el-table-column label="变更金额" prop="changeAmount" width="100" />
|
||||
<el-table-column label="变更后" prop="resultAmount" width="100" />
|
||||
<el-table-column label="时间" width="160"><template slot-scope="s">{{ parseTime(s.row.createTime) }}</template></el-table-column>
|
||||
</el-table>
|
||||
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listSubteamGroupBalance } from '@/api/subteam'
|
||||
export default {
|
||||
name: 'SubteamGroupBalance',
|
||||
data() {
|
||||
return {
|
||||
loading: true,
|
||||
showSearch: true,
|
||||
list: [],
|
||||
total: 0,
|
||||
queryParams: { pageNum: 1, pageSize: 10, type: undefined, relationOrderNo: undefined }
|
||||
}
|
||||
},
|
||||
created() { this.getList() },
|
||||
methods: {
|
||||
getList() {
|
||||
this.loading = true
|
||||
listSubteamGroupBalance(this.queryParams).then(res => {
|
||||
this.list = res.rows
|
||||
this.total = res.total
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
handleQuery() { this.queryParams.pageNum = 1; this.getList() },
|
||||
resetQuery() { this.resetForm('queryForm'); this.handleQuery() }
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
<el-row :gutter="16" v-loading="loading">
|
||||
<el-col :span="8">
|
||||
<el-card shadow="hover"><div class="metric-title">团队 ID</div><div class="metric-val">{{ info.deptId }}</div></el-card>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-card shadow="hover"><div class="metric-title">团队名称</div><div class="metric-val">{{ info.deptName }}</div></el-card>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-card shadow="hover"><div class="metric-title">积分余额(部门)</div><div class="metric-val">{{ info.balance }}</div></el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="16" style="margin-top:16px">
|
||||
<el-col :span="8">
|
||||
<el-card shadow="hover"><div class="metric-title">AI用户数(实时)</div><div class="metric-val">{{ info.aiUserCount }}</div></el-card>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-card shadow="hover"><div class="metric-title">近 7 日消耗积分 <span class="hint">(5 分钟缓存)</span></div><div class="metric-val">{{ info.last7DaysConsumeScore }}</div></el-card>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-card shadow="hover"><div class="metric-title">近 7 日成功订单数 <span class="hint">(5 分钟缓存)</span></div><div class="metric-val">{{ info.last7DaysOrderCount }}</div></el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getSubteamOverview } from '@/api/subteam'
|
||||
|
||||
export default {
|
||||
name: 'SubteamOverview',
|
||||
data() {
|
||||
return {
|
||||
loading: true,
|
||||
info: {}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.load()
|
||||
},
|
||||
methods: {
|
||||
load() {
|
||||
this.loading = true
|
||||
getSubteamOverview().then(res => {
|
||||
this.info = res.data || {}
|
||||
this.loading = false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.metric-title { color: #909399; font-size: 13px; }
|
||||
.metric-val { font-size: 22px; margin-top: 8px; font-weight: 600; }
|
||||
.hint { font-size: 12px; color: #909399; }
|
||||
</style>
|
||||
|
|
@ -0,0 +1,300 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
<el-form v-show="showSearch" ref="queryForm" :model="queryParams" size="small" :inline="true">
|
||||
<el-form-item label="账号" prop="username">
|
||||
<el-input v-model="queryParams.username" placeholder="账号" clearable @keyup.enter.native="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="手机号" prop="phone">
|
||||
<el-input v-model="queryParams.phone" placeholder="手机号" clearable @keyup.enter.native="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-select v-model="queryParams.status" placeholder="状态" clearable>
|
||||
<el-option label="正常" :value="0" />
|
||||
<el-option label="停用" :value="1" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button v-hasPermi="['subteam:user:add']" type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd">新增</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button v-hasPermi="['subteam:user:edit']" type="success" plain icon="el-icon-edit" size="mini" :disabled="single" @click="handleUpdate">修改</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button v-hasPermi="['subteam:user:remove']" type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete">删除</el-button>
|
||||
</el-col>
|
||||
<right-toolbar :show-search.sync="showSearch" @queryTable="getList" />
|
||||
</el-row>
|
||||
|
||||
<el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="50" />
|
||||
<el-table-column label="主键ID" prop="id" width="80" />
|
||||
<el-table-column label="账号" prop="username" />
|
||||
<el-table-column label="昵称" prop="nickname" />
|
||||
<el-table-column label="部门" prop="deptName" />
|
||||
<el-table-column label="手机" prop="phone" width="120" />
|
||||
<el-table-column label="状态" width="80">
|
||||
<template slot-scope="scope">
|
||||
<dict-tag :options="dict.type.sys_normal_disable" :value="String(scope.row.status)" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="320">
|
||||
<template slot-scope="scope">
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-download"
|
||||
@click="openDeptScoreDialog(scope.row, 'issue')"
|
||||
v-hasPermi="['ai:user:deptScoreIssue']"
|
||||
>下放积分</el-button>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-upload2"
|
||||
@click="openDeptScoreDialog(scope.row, 'reclaim')"
|
||||
v-hasPermi="['ai:user:deptScoreReclaim']"
|
||||
>回收积分</el-button>
|
||||
<el-button v-hasPermi="['subteam:user:edit']" size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)">修改</el-button>
|
||||
<el-button v-hasPermi="['subteam:user:resetPwd']" size="mini" type="text" icon="el-icon-key" @click="handleResetPwd(scope.row)">密码</el-button>
|
||||
<el-button v-hasPermi="['subteam:user:remove']" size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" />
|
||||
|
||||
<el-dialog :title="title" :visible.sync="open" width="640px" append-to-body>
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="88px">
|
||||
<el-form-item label="昵称" prop="nickname"><el-input v-model="form.nickname" /></el-form-item>
|
||||
<el-row v-if="!form.id">
|
||||
<el-col :span="12"><el-form-item label="账号" prop="username"><el-input v-model="form.username" /></el-form-item></el-col>
|
||||
<el-col :span="12"><el-form-item label="密码" prop="password"><el-input v-model="form.password" type="password" show-password /></el-form-item></el-col>
|
||||
</el-row>
|
||||
<el-form-item label="手机" prop="phone"><el-input v-model="form.phone" /></el-form-item>
|
||||
<el-form-item label="邮箱" prop="email"><el-input v-model="form.email" /></el-form-item>
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-radio-group v-model="form.status">
|
||||
<el-radio :label="0">正常</el-radio>
|
||||
<el-radio :label="1">停用</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注"><el-input v-model="form.remark" type="textarea" /></el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<el-dialog
|
||||
:title="deptScoreMode === 'issue' ? '下放积分' : '回收积分'"
|
||||
:visible.sync="deptScoreOpen"
|
||||
width="480px"
|
||||
append-to-body
|
||||
@close="cancelDeptScore"
|
||||
>
|
||||
<el-form ref="deptScoreFormRef" :model="deptScoreForm" :rules="deptScoreRules" label-width="88px">
|
||||
<el-form-item label="用户账号">
|
||||
<span>{{ deptScoreForm.username }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="积分数量" prop="amount">
|
||||
<el-input-number
|
||||
v-model="deptScoreForm.amount"
|
||||
:min="1"
|
||||
:max="100000000"
|
||||
:precision="0"
|
||||
:step="1"
|
||||
controls-position="right"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input
|
||||
v-model="deptScoreForm.remark"
|
||||
type="textarea"
|
||||
:rows="2"
|
||||
maxlength="50"
|
||||
show-word-limit
|
||||
placeholder="选填,最多50字"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="submitDeptScore">确 定</el-button>
|
||||
<el-button @click="cancelDeptScore">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
listSubteamUser, getSubteamUser, addSubteamUser, updateSubteamUser, delSubteamUser,
|
||||
resetSubteamUserPwd
|
||||
} from '@/api/subteam'
|
||||
import { issueDeptScore, reclaimDeptScore } from '@/api/ai/user'
|
||||
|
||||
export default {
|
||||
name: 'SubteamUser',
|
||||
dicts: ['sys_normal_disable'],
|
||||
data() {
|
||||
return {
|
||||
loading: true,
|
||||
showSearch: true,
|
||||
userList: [],
|
||||
total: 0,
|
||||
ids: [],
|
||||
single: true,
|
||||
multiple: true,
|
||||
title: '',
|
||||
open: false,
|
||||
deptScoreOpen: false,
|
||||
deptScoreMode: 'issue',
|
||||
deptScoreForm: {
|
||||
userId: null,
|
||||
username: '',
|
||||
amount: undefined,
|
||||
remark: ''
|
||||
},
|
||||
deptScoreRules: {
|
||||
amount: [
|
||||
{ required: true, message: '请输入积分数量', trigger: 'blur' },
|
||||
{
|
||||
type: 'number',
|
||||
min: 1,
|
||||
max: 100000000,
|
||||
message: '请输入 1~100000000 的整数',
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
remark: [{ max: 50, message: '备注最多50个字', trigger: 'blur' }]
|
||||
},
|
||||
queryParams: { pageNum: 1, pageSize: 10, username: undefined, phone: undefined, status: undefined },
|
||||
form: {},
|
||||
rules: {
|
||||
nickname: [{ required: true, message: '必填', trigger: 'blur' }],
|
||||
username: [{ required: true, message: '必填', trigger: 'blur' }],
|
||||
password: [{ required: true, message: '必填', trigger: 'blur' }],
|
||||
email: [{ type: 'email', message: '邮箱格式', trigger: ['blur', 'change'] }]
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getList()
|
||||
},
|
||||
methods: {
|
||||
getList() {
|
||||
this.loading = true
|
||||
listSubteamUser(this.queryParams).then(res => {
|
||||
this.userList = res.rows
|
||||
this.total = res.total
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
handleQuery() {
|
||||
this.queryParams.pageNum = 1
|
||||
this.getList()
|
||||
},
|
||||
resetQuery() {
|
||||
this.resetForm('queryForm')
|
||||
this.handleQuery()
|
||||
},
|
||||
handleSelectionChange(rows) {
|
||||
this.ids = rows.map(r => r.id)
|
||||
this.single = rows.length !== 1
|
||||
this.multiple = !rows.length
|
||||
},
|
||||
reset() {
|
||||
this.form = { id: undefined, username: undefined, nickname: undefined, password: undefined,
|
||||
phone: undefined, email: undefined, status: 0, remark: undefined }
|
||||
this.resetForm('form')
|
||||
},
|
||||
handleAdd() {
|
||||
this.reset()
|
||||
this.open = true
|
||||
this.title = '新增AI用户'
|
||||
},
|
||||
handleUpdate(row) {
|
||||
this.reset()
|
||||
const id = row.id || this.ids[0]
|
||||
getSubteamUser(id).then(r => {
|
||||
this.form = r.data || {}
|
||||
this.form.status = Number(this.form.status || 0)
|
||||
this.open = true
|
||||
this.title = '修改AI用户'
|
||||
})
|
||||
},
|
||||
submitForm() {
|
||||
this.$refs.form.validate(valid => {
|
||||
if (!valid) return
|
||||
if (this.form.id) {
|
||||
updateSubteamUser(this.form).then(() => { this.$modal.msgSuccess('成功'); this.open = false; this.getList() })
|
||||
} else {
|
||||
addSubteamUser(this.form).then(() => { this.$modal.msgSuccess('成功'); this.open = false; this.getList() })
|
||||
}
|
||||
})
|
||||
},
|
||||
cancel() { this.open = false },
|
||||
handleDelete(row) {
|
||||
const userIds = row.id || this.ids
|
||||
this.$modal.confirm('确认删除?').then(() => delSubteamUser(userIds)).then(() => { this.getList(); this.$modal.msgSuccess('已删除') }).catch(() => {})
|
||||
},
|
||||
handleResetPwd(row) {
|
||||
this.$prompt('新密码', '重置', { inputType: 'password' }).then(({ value }) => {
|
||||
resetSubteamUserPwd({ id: row.id, password: value }).then(() => this.$modal.msgSuccess('已重置'))
|
||||
}).catch(() => {})
|
||||
},
|
||||
openDeptScoreDialog(row, mode) {
|
||||
if (!row.deptId) {
|
||||
this.$modal.msgWarning('请先分配归属部门后再操作积分')
|
||||
return
|
||||
}
|
||||
this.deptScoreMode = mode
|
||||
this.deptScoreForm = {
|
||||
userId: row.id,
|
||||
username: row.username || row.userId || '',
|
||||
amount: undefined,
|
||||
remark: ''
|
||||
}
|
||||
this.deptScoreOpen = true
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.deptScoreFormRef) {
|
||||
this.$refs.deptScoreFormRef.clearValidate()
|
||||
}
|
||||
})
|
||||
},
|
||||
submitDeptScore() {
|
||||
this.$refs.deptScoreFormRef.validate(valid => {
|
||||
if (!valid) {
|
||||
return
|
||||
}
|
||||
const raw = this.deptScoreForm.amount
|
||||
const amount = typeof raw === 'number' ? Math.trunc(raw) : parseInt(String(raw), 10)
|
||||
if (!Number.isFinite(amount) || amount < 1 || amount > 100000000) {
|
||||
this.$modal.msgWarning('请输入 1~100000000 的整数积分')
|
||||
return
|
||||
}
|
||||
const payload = {
|
||||
userId: this.deptScoreForm.userId,
|
||||
amount,
|
||||
remark: this.deptScoreForm.remark || undefined
|
||||
}
|
||||
const req = this.deptScoreMode === 'issue' ? issueDeptScore : reclaimDeptScore
|
||||
req(payload).then(() => {
|
||||
this.$modal.msgSuccess('操作成功')
|
||||
this.deptScoreOpen = false
|
||||
this.getList()
|
||||
})
|
||||
})
|
||||
},
|
||||
cancelDeptScore() {
|
||||
this.deptScoreOpen = false
|
||||
this.deptScoreForm = { userId: null, username: '', amount: undefined, remark: '' }
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
<el-form v-show="showSearch" ref="queryForm" :model="queryParams" size="small" :inline="true">
|
||||
<el-form-item label="用户ID" prop="userId">
|
||||
<el-input v-model="queryParams.userId" clearable @keyup.enter.native="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="类型" prop="type">
|
||||
<el-input v-model="queryParams.type" clearable placeholder="类型码" @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 class="mb8"><right-toolbar :show-search.sync="showSearch" @queryTable="getList" /></el-row>
|
||||
<el-table v-loading="loading" :data="list">
|
||||
<el-table-column label="ID" prop="id" width="80" />
|
||||
<el-table-column label="用户ID" prop="userId" width="90" />
|
||||
<el-table-column label="账号" prop="nickname" min-width="100" />
|
||||
<el-table-column label="类型" prop="type" width="80" />
|
||||
<el-table-column label="变更" prop="changeAmount" width="100" />
|
||||
<el-table-column label="余额" prop="resultAmount" width="100" />
|
||||
<el-table-column label="时间" width="160"><template slot-scope="s">{{ parseTime(s.row.createTime) }}</template></el-table-column>
|
||||
</el-table>
|
||||
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listSubteamUserBalance } from '@/api/subteam'
|
||||
export default {
|
||||
name: 'SubteamUserBalance',
|
||||
data() {
|
||||
return {
|
||||
loading: true,
|
||||
showSearch: true,
|
||||
list: [],
|
||||
total: 0,
|
||||
queryParams: { pageNum: 1, pageSize: 10, userId: undefined, type: undefined }
|
||||
}
|
||||
},
|
||||
created() { this.getList() },
|
||||
methods: {
|
||||
getList() {
|
||||
this.loading = true
|
||||
listSubteamUserBalance(this.queryParams).then(res => {
|
||||
this.list = res.rows
|
||||
this.total = res.total
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
handleQuery() { this.queryParams.pageNum = 1; this.getList() },
|
||||
resetQuery() { this.resetForm('queryForm'); this.handleQuery() }
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,138 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
<el-form v-show="showSearch" ref="queryForm" :model="queryParams" size="small" :inline="true">
|
||||
<el-form-item label="订单号" prop="orderNum">
|
||||
<el-input v-model="queryParams.orderNum" clearable @keyup.enter.native="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="用户ID" prop="userId">
|
||||
<el-input v-model="queryParams.userId" clearable @keyup.enter.native="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-select v-model="queryParams.status" clearable placeholder="状态">
|
||||
<el-option label="进行中" :value="0" /><el-option label="已完成" :value="1" /><el-option label="失败" :value="2" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-row class="mb8"><right-toolbar :show-search.sync="showSearch" @queryTable="getList" /></el-row>
|
||||
<el-table v-loading="loading" :data="list">
|
||||
<el-table-column label="ID" prop="id" width="70" />
|
||||
<el-table-column label="订单号" prop="orderNum" min-width="120" show-overflow-tooltip />
|
||||
<el-table-column label="用户ID" prop="userId" width="90" />
|
||||
<el-table-column label="金额" prop="amount" width="90" />
|
||||
<el-table-column label="状态" prop="status" width="80" />
|
||||
<el-table-column label="结果预览" min-width="220">
|
||||
<template slot-scope="s">
|
||||
<div v-if="extractVideoUrl(s.row.result)">
|
||||
<video
|
||||
:src="extractVideoUrl(s.row.result)"
|
||||
controls
|
||||
preload="metadata"
|
||||
style="width: 180px; max-height: 100px; border-radius: 4px;"
|
||||
/>
|
||||
</div>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="创建时间" prop="createTime" width="160"><template slot-scope="s">{{ parseTime(s.row.createTime) }}</template></el-table-column>
|
||||
<el-table-column label="操作" width="90" fixed="right">
|
||||
<template slot-scope="s">
|
||||
<el-button type="text" size="mini" @click="handleDetail(s.row)">详情</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" />
|
||||
|
||||
<el-dialog title="订单详情" :visible.sync="detailVisible" width="720px" append-to-body>
|
||||
<el-descriptions :column="1" border size="small">
|
||||
<el-descriptions-item v-for="(value, key) in detailData" :key="key" :label="key">
|
||||
<pre v-if="isObjectValue(value)" style="margin: 0; white-space: pre-wrap;">{{ formatJson(value) }}</pre>
|
||||
<span v-else>{{ value === null || value === undefined || value === '' ? '-' : value }}</span>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<span slot="footer">
|
||||
<el-button size="mini" @click="detailVisible = false">关闭</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listSubteamVideoOrder } from '@/api/subteam'
|
||||
export default {
|
||||
name: 'SubteamVideoOrder',
|
||||
data() {
|
||||
return {
|
||||
loading: true,
|
||||
showSearch: true,
|
||||
list: [],
|
||||
total: 0,
|
||||
detailVisible: false,
|
||||
detailData: {},
|
||||
queryParams: { pageNum: 1, pageSize: 10, orderNum: undefined, userId: undefined, status: undefined }
|
||||
}
|
||||
},
|
||||
created() { this.getList() },
|
||||
methods: {
|
||||
getList() {
|
||||
this.loading = true
|
||||
listSubteamVideoOrder(this.queryParams).then(res => {
|
||||
this.list = res.rows
|
||||
this.total = res.total
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
extractVideoUrl(result) {
|
||||
if (!result) return ''
|
||||
if (typeof result === 'string') {
|
||||
const value = result.trim()
|
||||
if (!value) return ''
|
||||
if (/^https?:\/\/|^\/\//.test(value)) return value
|
||||
try {
|
||||
const parsed = JSON.parse(value)
|
||||
return this.extractVideoUrl(parsed)
|
||||
} catch (e) {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
if (Array.isArray(result)) {
|
||||
for (let i = 0; i < result.length; i += 1) {
|
||||
const url = this.extractVideoUrl(result[i])
|
||||
if (url) return url
|
||||
}
|
||||
return ''
|
||||
}
|
||||
if (typeof result === 'object') {
|
||||
const directKeys = ['videoUrl', 'url', 'resultUrl', 'playUrl', 'output', 'fileUrl']
|
||||
for (let i = 0; i < directKeys.length; i += 1) {
|
||||
const key = directKeys[i]
|
||||
if (result[key]) {
|
||||
const url = this.extractVideoUrl(result[key])
|
||||
if (url) return url
|
||||
}
|
||||
}
|
||||
}
|
||||
return ''
|
||||
},
|
||||
handleDetail(row) {
|
||||
this.detailData = row || {}
|
||||
this.detailVisible = true
|
||||
},
|
||||
isObjectValue(value) {
|
||||
return value !== null && typeof value === 'object'
|
||||
},
|
||||
formatJson(value) {
|
||||
try {
|
||||
return JSON.stringify(value, null, 2)
|
||||
} catch (e) {
|
||||
return String(value)
|
||||
}
|
||||
},
|
||||
handleQuery() { this.queryParams.pageNum = 1; this.getList() },
|
||||
resetQuery() { this.resetForm('queryForm'); this.handleQuery() }
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -26,16 +26,6 @@
|
|||
</el-form>
|
||||
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
icon="el-icon-plus"
|
||||
size="mini"
|
||||
@click="handleAdd"
|
||||
v-hasPermi="['system:dept:add']"
|
||||
>新增</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="info"
|
||||
|
|
@ -57,10 +47,10 @@
|
|||
:tree-props="{children: 'children', hasChildren: 'hasChildren'}"
|
||||
>
|
||||
<el-table-column prop="deptName" label="部门名称" width="260"></el-table-column>
|
||||
<el-table-column prop="orderNum" label="排序" width="80"></el-table-column>
|
||||
<el-table-column prop="balance" label="剩余积分" width="200" align="right">
|
||||
<el-table-column prop="orderNum" label="排序" width="200"></el-table-column>
|
||||
<el-table-column prop="maxUserCount" label="账号上限" width="100" align="center">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.balance != null ? scope.row.balance : '—' }}</span>
|
||||
<span>{{ scope.row.maxUserCount != null && scope.row.maxUserCount > 0 ? scope.row.maxUserCount : '不限制' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="status" label="状态" width="100">
|
||||
|
|
@ -68,20 +58,13 @@
|
|||
<dict-tag :options="dict.type.sys_normal_disable" :value="scope.row.status"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="创建时间" align="center" prop="createTime" width="150">
|
||||
<el-table-column label="创建时间" align="center" prop="createTime" width="200">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ parseTime(scope.row.createTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-plus"
|
||||
@click="handleAdd(scope.row)"
|
||||
v-hasPermi="['system:dept:add']"
|
||||
>新增</el-button>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
|
|
@ -89,6 +72,14 @@
|
|||
@click="handleUpdate(scope.row)"
|
||||
v-hasPermi="['system:dept:edit']"
|
||||
>修改</el-button>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-plus"
|
||||
@click="handleAdd(scope.row)"
|
||||
v-if="isFirstLevelRow(scope.row)"
|
||||
v-hasPermi="['system:dept:add']"
|
||||
>新增</el-button>
|
||||
<el-button
|
||||
v-if="scope.row.parentId != 0"
|
||||
size="mini"
|
||||
|
|
@ -97,20 +88,6 @@
|
|||
@click="handleDelete(scope.row)"
|
||||
v-hasPermi="['system:dept:remove']"
|
||||
>删除</el-button>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-wallet"
|
||||
@click="handleChargeRefund(scope.row)"
|
||||
v-hasPermi="['system:dept:chargeRefund']"
|
||||
>充值/退款</el-button>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-s-operation"
|
||||
@click="handleEditScore(scope.row)"
|
||||
v-hasPermi="['system:dept:chargeRefund']"
|
||||
>积分更正</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
|
@ -133,31 +110,31 @@
|
|||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="显示排序" prop="orderNum">
|
||||
<el-input-number v-model="form.orderNum" controls-position="right" :min="0" />
|
||||
<el-input-number v-model="form.orderNum" controls-position="right" :min="0" :disabled="isFirstLevelEditForm" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="负责人" prop="leader">
|
||||
<el-input v-model="form.leader" placeholder="请输入负责人" maxlength="20" />
|
||||
<el-input v-model="form.leader" placeholder="请输入负责人" maxlength="20" :disabled="isFirstLevelEditForm" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="联系电话" prop="phone">
|
||||
<el-input v-model="form.phone" placeholder="请输入联系电话" maxlength="11" />
|
||||
<el-input v-model="form.phone" placeholder="请输入联系电话" maxlength="11" :disabled="isFirstLevelEditForm" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="邮箱" prop="email">
|
||||
<el-input v-model="form.email" placeholder="请输入邮箱" maxlength="50" />
|
||||
<el-input v-model="form.email" placeholder="请输入邮箱" maxlength="50" :disabled="isFirstLevelEditForm" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="部门状态">
|
||||
<el-radio-group v-model="form.status">
|
||||
<el-radio-group v-model="form.status" :disabled="isFirstLevelEditForm">
|
||||
<el-radio
|
||||
v-for="dict in dict.type.sys_normal_disable"
|
||||
:key="dict.value"
|
||||
|
|
@ -167,6 +144,25 @@
|
|||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="账号上限" prop="maxUserCount">
|
||||
<el-input-number
|
||||
v-model="form.maxUserCount"
|
||||
:min="0"
|
||||
:max="999999"
|
||||
:precision="0"
|
||||
controls-position="right"
|
||||
placeholder="0=不限制"
|
||||
style="width: 100%"
|
||||
:disabled="isFirstLevelEditForm"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<p class="model-parm-hint" style="margin: 0; padding-top: 8px">限制本部门下「启用」状态账号数量;0 或不填表示不限制。</p>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row v-if="isSecondLevelCompanyForm">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="Byte API Key">
|
||||
|
|
@ -230,95 +226,11 @@
|
|||
</el-row>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<span v-if="isFirstLevelEditForm" class="form-tip">一级部门仅允许修改名称</span>
|
||||
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog
|
||||
:title="'充值/退款 — ' + (chargeRefundForm.deptName || '')"
|
||||
:visible.sync="chargeRefundOpen"
|
||||
width="520px"
|
||||
append-to-body
|
||||
@close="resetChargeRefund"
|
||||
>
|
||||
<el-form ref="chargeRefundFormRef" :model="chargeRefundForm" :rules="chargeRefundRules" label-width="88px">
|
||||
<el-form-item label="类型" prop="orderType">
|
||||
<el-radio-group v-model="chargeRefundForm.orderType">
|
||||
<el-radio :label="0">充值</el-radio>
|
||||
<el-radio :label="1">退款</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="金额" prop="money">
|
||||
<el-input
|
||||
:value="chargeRefundMoneyDisplay"
|
||||
placeholder="财务记录(元),如 9,999,999.00"
|
||||
clearable
|
||||
@input="onChargeRefundMoneyInput"
|
||||
@blur="onChargeRefundMoneyBlur"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="积分" prop="amount">
|
||||
<el-input
|
||||
:value="chargeRefundAmountDisplay"
|
||||
placeholder="变动积分,如 99,999,999"
|
||||
clearable
|
||||
@input="onChargeRefundAmountInput"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input
|
||||
v-model="chargeRefundForm.remark"
|
||||
type="textarea"
|
||||
:rows="2"
|
||||
maxlength="50"
|
||||
show-word-limit
|
||||
placeholder="选填,最多50字"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="submitChargeRefund">确 定</el-button>
|
||||
<el-button @click="chargeRefundOpen = false">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog
|
||||
:title="'积分更正 — ' + (editScoreForm.deptName || '')"
|
||||
:visible.sync="editScoreOpen"
|
||||
width="520px"
|
||||
append-to-body
|
||||
@close="resetEditScore"
|
||||
>
|
||||
<el-form ref="editScoreFormRef" :model="editScoreForm" :rules="editScoreRules" label-width="88px">
|
||||
<el-form-item label="积分" prop="score">
|
||||
<el-input-number
|
||||
v-model="editScoreForm.score"
|
||||
:precision="0"
|
||||
:step="1"
|
||||
:min="-100000000"
|
||||
:max="100000000"
|
||||
controls-position="right"
|
||||
class="edit-score-input-number"
|
||||
placeholder="正数增加,负数扣减,不能为0"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input
|
||||
v-model="editScoreForm.remark"
|
||||
type="textarea"
|
||||
:rows="2"
|
||||
maxlength="50"
|
||||
show-word-limit
|
||||
placeholder="必填,最多50字"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="submitEditScore">确 定</el-button>
|
||||
<el-button @click="editScoreOpen = false">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
@ -345,23 +257,15 @@
|
|||
color: #909399;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.edit-score-input-number {
|
||||
width: 100%;
|
||||
.form-tip {
|
||||
margin-right: 16px;
|
||||
color: #e6a23c;
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import { listDept, getDept, delDept, addDept, updateDept, listDeptExcludeChild, chargeRefundDept, editScore } from "@/api/system/dept"
|
||||
import {
|
||||
WESTERN_MONEY_MAX,
|
||||
sanitizeMoneyDigits,
|
||||
formatMoneyWesternDisplay,
|
||||
moneyStringToNumber,
|
||||
formatMoneyWesternFinal,
|
||||
sanitizeIntDigits,
|
||||
formatIntWesternDisplay,
|
||||
intStringToNumber
|
||||
} from "@/utils/westernNumberFormat"
|
||||
import { listDept, getDept, delDept, addDept, updateDept, listDeptExcludeChild } from "@/api/system/dept"
|
||||
import Treeselect from "@riophae/vue-treeselect"
|
||||
import "@riophae/vue-treeselect/dist/vue-treeselect.css"
|
||||
|
||||
|
|
@ -394,76 +298,8 @@ export default {
|
|||
},
|
||||
// 表单参数
|
||||
form: {},
|
||||
originalForm: {},
|
||||
modelParamRows: [{ label: '', value: '' }],
|
||||
chargeRefundOpen: false,
|
||||
chargeRefundMoneyDisplay: "",
|
||||
chargeRefundAmountDisplay: "",
|
||||
chargeRefundForm: {
|
||||
deptId: undefined,
|
||||
deptName: "",
|
||||
orderType: 0,
|
||||
money: undefined,
|
||||
amount: undefined,
|
||||
remark: ""
|
||||
},
|
||||
chargeRefundRules: {
|
||||
orderType: [
|
||||
{ required: true, message: "类型不能为空", trigger: "change" }
|
||||
],
|
||||
money: [
|
||||
{ required: true, message: "金额不能为空", trigger: "blur" },
|
||||
{ type: "number", min: 0, max: 10000000, message: "金额须在 0~10000000 之间", trigger: "blur" }
|
||||
],
|
||||
amount: [
|
||||
{ required: true, message: "积分不能为空", trigger: "blur" },
|
||||
{ type: "number", min: 1, max: 100000000, message: "积分须在 1~100000000 之间", 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("积分须在 -100000000~100000000 之间(不含0)"))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
},
|
||||
trigger: "blur"
|
||||
}
|
||||
],
|
||||
remark: [
|
||||
{ required: true, message: "备注不能为空", trigger: "blur" },
|
||||
{
|
||||
validator(rule, value, callback) {
|
||||
if (!value || String(value).trim() === "") {
|
||||
callback(new Error("备注不能为空"))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
},
|
||||
trigger: "blur"
|
||||
},
|
||||
{ max: 50, message: "备注不能超过50个字符", trigger: "blur" }
|
||||
]
|
||||
},
|
||||
// 表单校验
|
||||
rules: {
|
||||
parentId: [
|
||||
|
|
@ -506,9 +342,35 @@ export default {
|
|||
return true
|
||||
}
|
||||
return false
|
||||
},
|
||||
isFirstLevelEditForm() {
|
||||
return this.form.deptId !== undefined && this.isFirstLevelRow(this.form)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
isFirstLevelRow(row) {
|
||||
if (!row) {
|
||||
return false
|
||||
}
|
||||
return Number(row.parentId) === 0 && String(row.ancestors || "") === "0"
|
||||
},
|
||||
isSecondLevelRow(row) {
|
||||
if (!row) {
|
||||
return false
|
||||
}
|
||||
const ancestors = String(row.ancestors || "").split(",").filter(Boolean)
|
||||
return ancestors.length === 2
|
||||
},
|
||||
getFirstLevelDeptOptions(nodes) {
|
||||
if (!Array.isArray(nodes)) {
|
||||
return []
|
||||
}
|
||||
return nodes.filter(item => this.isFirstLevelRow(item)).map(item => {
|
||||
const current = { ...item }
|
||||
delete current.children
|
||||
return current
|
||||
})
|
||||
},
|
||||
syncModelRowsFromForm() {
|
||||
this.modelParamRows = [{ label: '', value: '' }]
|
||||
const raw = this.form.modelParm
|
||||
|
|
@ -578,11 +440,13 @@ export default {
|
|||
leader: undefined,
|
||||
phone: undefined,
|
||||
email: undefined,
|
||||
maxUserCount: undefined,
|
||||
byteApiKey: undefined,
|
||||
project: undefined,
|
||||
modelParm: undefined,
|
||||
status: "0"
|
||||
}
|
||||
this.originalForm = {}
|
||||
this.modelParamRows = [{ label: '', value: '' }]
|
||||
this.resetForm("form")
|
||||
},
|
||||
|
|
@ -598,13 +462,17 @@ export default {
|
|||
/** 新增按钮操作 */
|
||||
handleAdd(row) {
|
||||
this.reset()
|
||||
if (row != undefined) {
|
||||
if (row !== undefined) {
|
||||
if (!this.isFirstLevelRow(row)) {
|
||||
this.$modal.msgError("仅允许在一级部门下新增二级部门")
|
||||
return
|
||||
}
|
||||
this.form.parentId = row.deptId
|
||||
}
|
||||
this.open = true
|
||||
this.title = "添加部门"
|
||||
this.title = "添加二级部门"
|
||||
listDept().then(response => {
|
||||
this.deptOptions = this.handleTree(response.data, "deptId")
|
||||
this.deptOptions = this.getFirstLevelDeptOptions(this.handleTree(response.data, "deptId"))
|
||||
})
|
||||
},
|
||||
/** 展开/折叠操作 */
|
||||
|
|
@ -620,11 +488,13 @@ export default {
|
|||
this.reset()
|
||||
getDept(row.deptId).then(response => {
|
||||
this.form = response.data
|
||||
this.originalForm = { ...response.data }
|
||||
this.syncModelRowsFromForm()
|
||||
this.open = true
|
||||
this.title = "修改部门"
|
||||
listDeptExcludeChild(row.deptId).then(response => {
|
||||
this.deptOptions = this.handleTree(response.data, "deptId")
|
||||
const allOptions = this.handleTree(response.data, "deptId")
|
||||
this.deptOptions = this.getFirstLevelDeptOptions(allOptions)
|
||||
if (this.deptOptions.length == 0) {
|
||||
const noResultsOptions = { deptId: this.form.parentId, deptName: this.form.parentName, children: [] }
|
||||
this.deptOptions.push(noResultsOptions)
|
||||
|
|
@ -637,7 +507,24 @@ export default {
|
|||
this.$refs["form"].validate(valid => {
|
||||
if (valid) {
|
||||
this.buildModelParmPayload()
|
||||
if (this.form.deptId == undefined && !this.deptOptions.some(item => Number(item.deptId) === Number(this.form.parentId))) {
|
||||
this.$modal.msgError("仅允许在一级部门下创建二级部门")
|
||||
return
|
||||
}
|
||||
if (this.form.deptId != undefined) {
|
||||
if (this.isFirstLevelEditForm) {
|
||||
const oldDept = this.originalForm || {}
|
||||
this.form.parentId = oldDept.parentId
|
||||
this.form.orderNum = oldDept.orderNum
|
||||
this.form.leader = oldDept.leader
|
||||
this.form.phone = oldDept.phone
|
||||
this.form.email = oldDept.email
|
||||
this.form.status = oldDept.status
|
||||
this.form.maxUserCount = oldDept.maxUserCount
|
||||
this.form.byteApiKey = oldDept.byteApiKey
|
||||
this.form.project = oldDept.project
|
||||
this.form.modelParm = oldDept.modelParm
|
||||
}
|
||||
updateDept(this.form).then(response => {
|
||||
this.$modal.msgSuccess("修改成功")
|
||||
this.open = false
|
||||
|
|
@ -653,132 +540,6 @@ export default {
|
|||
}
|
||||
})
|
||||
},
|
||||
resetChargeRefund() {
|
||||
this.chargeRefundMoneyDisplay = ""
|
||||
this.chargeRefundAmountDisplay = ""
|
||||
this.chargeRefundForm = {
|
||||
deptId: undefined,
|
||||
deptName: "",
|
||||
orderType: 0,
|
||||
money: undefined,
|
||||
amount: undefined,
|
||||
remark: ""
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.chargeRefundFormRef) {
|
||||
this.$refs.chargeRefundFormRef.clearValidate()
|
||||
}
|
||||
})
|
||||
},
|
||||
handleChargeRefund(row) {
|
||||
this.chargeRefundMoneyDisplay = ""
|
||||
this.chargeRefundAmountDisplay = ""
|
||||
this.chargeRefundForm = {
|
||||
deptId: row.deptId,
|
||||
deptName: row.deptName,
|
||||
orderType: 0,
|
||||
money: undefined,
|
||||
amount: undefined,
|
||||
remark: ""
|
||||
}
|
||||
this.chargeRefundOpen = true
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.chargeRefundFormRef) {
|
||||
this.$refs.chargeRefundFormRef.clearValidate()
|
||||
}
|
||||
})
|
||||
},
|
||||
onChargeRefundMoneyInput(val) {
|
||||
const sanitized = sanitizeMoneyDigits(val)
|
||||
if (!sanitized) {
|
||||
this.chargeRefundMoneyDisplay = ""
|
||||
this.chargeRefundForm.money = undefined
|
||||
return
|
||||
}
|
||||
const raw = parseFloat(sanitized)
|
||||
if (!isNaN(raw) && raw > WESTERN_MONEY_MAX) {
|
||||
this.chargeRefundForm.money = WESTERN_MONEY_MAX
|
||||
this.chargeRefundMoneyDisplay = formatMoneyWesternFinal(WESTERN_MONEY_MAX)
|
||||
return
|
||||
}
|
||||
this.chargeRefundMoneyDisplay = formatMoneyWesternDisplay(sanitized)
|
||||
this.chargeRefundForm.money = moneyStringToNumber(sanitized)
|
||||
},
|
||||
onChargeRefundMoneyBlur() {
|
||||
if (this.chargeRefundForm.money !== undefined && this.chargeRefundForm.money !== null) {
|
||||
this.chargeRefundMoneyDisplay = formatMoneyWesternFinal(this.chargeRefundForm.money)
|
||||
}
|
||||
},
|
||||
onChargeRefundAmountInput(val) {
|
||||
const digits = sanitizeIntDigits(val)
|
||||
this.chargeRefundAmountDisplay = digits === "" ? "" : formatIntWesternDisplay(digits)
|
||||
this.chargeRefundForm.amount = intStringToNumber(digits)
|
||||
},
|
||||
submitChargeRefund() {
|
||||
this.onChargeRefundMoneyBlur()
|
||||
this.$refs["chargeRefundFormRef"].validate(valid => {
|
||||
if (!valid) {
|
||||
return
|
||||
}
|
||||
const data = {
|
||||
deptId: this.chargeRefundForm.deptId,
|
||||
orderType: this.chargeRefundForm.orderType,
|
||||
money: this.chargeRefundForm.money,
|
||||
amount: this.chargeRefundForm.amount,
|
||||
remark: this.chargeRefundForm.remark ? this.chargeRefundForm.remark.trim() : undefined
|
||||
}
|
||||
chargeRefundDept(data).then(() => {
|
||||
this.$modal.msgSuccess("操作成功")
|
||||
this.chargeRefundOpen = false
|
||||
this.getList()
|
||||
})
|
||||
})
|
||||
},
|
||||
resetEditScore() {
|
||||
this.editScoreForm = {
|
||||
deptId: undefined,
|
||||
deptName: "",
|
||||
score: undefined,
|
||||
remark: ""
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.editScoreFormRef) {
|
||||
this.$refs.editScoreFormRef.clearValidate()
|
||||
}
|
||||
})
|
||||
},
|
||||
handleEditScore(row) {
|
||||
this.editScoreForm = {
|
||||
deptId: row.deptId,
|
||||
deptName: row.deptName,
|
||||
score: undefined,
|
||||
remark: ""
|
||||
}
|
||||
this.editScoreOpen = true
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.editScoreFormRef) {
|
||||
this.$refs.editScoreFormRef.clearValidate()
|
||||
}
|
||||
})
|
||||
},
|
||||
submitEditScore() {
|
||||
this.$refs["editScoreFormRef"].validate(valid => {
|
||||
if (!valid) {
|
||||
return
|
||||
}
|
||||
const remark = (this.editScoreForm.remark || "").trim()
|
||||
const data = {
|
||||
deptId: this.editScoreForm.deptId,
|
||||
score: this.editScoreForm.score,
|
||||
remark: remark
|
||||
}
|
||||
editScore(data).then(() => {
|
||||
this.$modal.msgSuccess("操作成功")
|
||||
this.editScoreOpen = false
|
||||
this.getList()
|
||||
})
|
||||
})
|
||||
},
|
||||
/** 删除按钮操作 */
|
||||
handleDelete(row) {
|
||||
this.$modal.confirm('是否确认删除名称为"' + row.deptName + '"的数据项?').then(function() {
|
||||
|
|
|
|||
|
|
@ -44,20 +44,7 @@
|
|||
inputType="password"
|
||||
:placeholder="`${$t('common.passwordPlaceholder')}`" />
|
||||
|
||||
<div class="login-link">
|
||||
<mf-button
|
||||
class="grey"
|
||||
type="text"
|
||||
@click="showForgot">
|
||||
{{ $t('common.forgotPassword') }}?
|
||||
</mf-button>
|
||||
</div>
|
||||
<div class="login-submit">
|
||||
<mf-button
|
||||
size="large"
|
||||
@click="showRegister">
|
||||
{{ $t('common.register') }}
|
||||
</mf-button>
|
||||
<mf-button
|
||||
size="large"
|
||||
type="primary"
|
||||
|
|
@ -67,25 +54,10 @@
|
|||
</mf-button>
|
||||
</div>
|
||||
</mf-dialog>
|
||||
<Forgot
|
||||
v-if="forgotVisible"
|
||||
:visible="forgotVisible"
|
||||
@open="forgotVisible = true"
|
||||
@back="back"
|
||||
@cancel="forgotVisible = false" />
|
||||
|
||||
<Register
|
||||
v-if="registerVisible"
|
||||
:visible="registerVisible"
|
||||
@cancel="registerVisible = false"
|
||||
@back="backFormRegister"
|
||||
@open="registerVisible = true" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Forgot from './Forgot.vue'
|
||||
import Register from './Register.vue'
|
||||
import { mapGetters } from 'vuex'
|
||||
import i18n from '@/lang/i18n'
|
||||
|
||||
|
|
@ -93,22 +65,16 @@ export default {
|
|||
data() {
|
||||
return {
|
||||
email: '',
|
||||
forgotVisible: false,
|
||||
emailVisible: false,
|
||||
registerVisible: false,
|
||||
loading: false,
|
||||
username: '',
|
||||
password: ''
|
||||
}
|
||||
},
|
||||
props: {
|
||||
visible: Boolean,
|
||||
register: Boolean
|
||||
},
|
||||
components: {
|
||||
Forgot,
|
||||
Register
|
||||
visible: Boolean
|
||||
},
|
||||
components: {},
|
||||
computed: {
|
||||
...mapGetters(['lang'])
|
||||
},
|
||||
|
|
@ -121,10 +87,6 @@ export default {
|
|||
// }
|
||||
this.username = ""
|
||||
this.password = ""
|
||||
let { inviteCode } = this.$route.query || {}
|
||||
if (inviteCode) {
|
||||
this.showRegister()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
cancel() {
|
||||
|
|
@ -132,24 +94,12 @@ export default {
|
|||
this.password = ''
|
||||
this.$emit('cancel')
|
||||
},
|
||||
showRegister() {
|
||||
this.registerVisible = true
|
||||
this.$emit('cancel')
|
||||
},
|
||||
changeLang(value) {
|
||||
if (value != this.lang) {
|
||||
this.$store.dispatch('main/setLanguage', value)
|
||||
i18n.global.locale = value
|
||||
}
|
||||
},
|
||||
back() {
|
||||
this.forgotVisible = false
|
||||
this.$emit('open')
|
||||
},
|
||||
backFormRegister() {
|
||||
this.registerVisible = false
|
||||
this.$emit('open')
|
||||
},
|
||||
login() {
|
||||
if (!this.username) {
|
||||
this.$message.error(this.$t('common.userEmailPlaceholder'))
|
||||
|
|
@ -191,10 +141,6 @@ export default {
|
|||
.catch((_) => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
showForgot() {
|
||||
this.forgotVisible = true
|
||||
this.$emit('cancel')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -324,36 +270,8 @@ export default {
|
|||
justify-content: center;
|
||||
margin-top: 30px;
|
||||
.mf-button {
|
||||
width: 160px;
|
||||
width: 220px;
|
||||
border-radius: 10px;
|
||||
margin: 0 14px;
|
||||
|
||||
&:first-child {
|
||||
color: #ffffff;
|
||||
background-color: #1a1a1a;
|
||||
&:hover {
|
||||
background-color: #262626;
|
||||
}
|
||||
&:active {
|
||||
background-color: #0d0d0d;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.login-link {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
color: #999;
|
||||
margin-top: 10px;
|
||||
.mf-button {
|
||||
padding: 0;
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
|
||||
&:hover {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,22 +42,10 @@
|
|||
</a-tabs>
|
||||
</div>
|
||||
</mf-dialog>
|
||||
<Forgot
|
||||
:visible="forgotVisible"
|
||||
@open="forgotVisible = true"
|
||||
@back="back"
|
||||
@cancel="forgotVisible = false" />
|
||||
<Register
|
||||
:visible="registerVisible"
|
||||
@cancel="registerVisible = false"
|
||||
@back="backFormRegister"
|
||||
@open="registerVisible = true" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Forgot from './Forgot.vue'
|
||||
import Register from './Register.vue'
|
||||
import UserAccount from './UserAccount.vue'
|
||||
import ResumeRecord from './ResumeRecord.vue'
|
||||
|
||||
|
|
@ -65,9 +53,7 @@ export default {
|
|||
data() {
|
||||
return {
|
||||
email: '',
|
||||
forgotVisible: false,
|
||||
emailVisible: false,
|
||||
registerVisible: false,
|
||||
loading: false,
|
||||
username: '',
|
||||
password: '',
|
||||
|
|
@ -75,22 +61,13 @@ export default {
|
|||
}
|
||||
},
|
||||
props: {
|
||||
visible: Boolean,
|
||||
register: Boolean
|
||||
visible: Boolean
|
||||
},
|
||||
components: {
|
||||
Forgot,
|
||||
Register,
|
||||
UserAccount,
|
||||
ResumeRecord
|
||||
},
|
||||
mounted() {
|
||||
if (this.register) {
|
||||
this.showRegister()
|
||||
setTimeout((_) => {
|
||||
this.$emit('cancel')
|
||||
}, 300)
|
||||
}
|
||||
window.addEventListener('message', (event) => {
|
||||
if (event.data.type === 'google-login') {
|
||||
const { token } = event.data
|
||||
|
|
@ -104,18 +81,6 @@ export default {
|
|||
})
|
||||
},
|
||||
methods: {
|
||||
showRegister() {
|
||||
this.registerVisible = true
|
||||
this.$emit('cancel')
|
||||
},
|
||||
back() {
|
||||
this.forgotVisible = false
|
||||
this.$emit('open')
|
||||
},
|
||||
backFormRegister() {
|
||||
this.registerVisible = false
|
||||
this.$emit('open')
|
||||
},
|
||||
backEmail() {
|
||||
this.emailVisible = false
|
||||
this.$emit('open')
|
||||
|
|
@ -148,10 +113,6 @@ export default {
|
|||
.catch((_) => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
showForgot() {
|
||||
this.forgotVisible = true
|
||||
this.$emit('cancel')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,7 +78,6 @@
|
|||
</div>
|
||||
|
||||
<Login
|
||||
:register="!$datas.isEmpty(inviteCode)"
|
||||
:visible="showLogin"
|
||||
@open="openLogin"
|
||||
@cancel="cancelLogin" />
|
||||
|
|
@ -118,7 +117,6 @@ export default {
|
|||
}
|
||||
],
|
||||
publishVisible: false,
|
||||
inviteCode: this.$route.query?.inviteCode,
|
||||
userVisible: false,
|
||||
logoUrl: null
|
||||
}
|
||||
|
|
@ -179,9 +177,6 @@ export default {
|
|||
}
|
||||
},
|
||||
mounted() {
|
||||
if (this.inviteCode) {
|
||||
this.openLogin()
|
||||
}
|
||||
this.getLogo()
|
||||
if (getToken()) {
|
||||
this.$store.dispatch('user/getInfo').catch(() => {})
|
||||
|
|
|
|||
|
|
@ -0,0 +1,104 @@
|
|||
package com.ruoyi.ai.controller;
|
||||
|
||||
import java.util.List;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.ai.domain.AiChargeRefundOrder;
|
||||
import com.ruoyi.ai.service.IAiChargeRefundOrderService;
|
||||
import com.ruoyi.common.utils.poi.ExcelUtil;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
|
||||
/**
|
||||
* 团队(部门)充值退款订单Controller
|
||||
*
|
||||
* @author shi
|
||||
* @date 2026-04-17
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/ai/order")
|
||||
public class AiChargeRefundOrderController extends BaseController
|
||||
{
|
||||
@Autowired
|
||||
private IAiChargeRefundOrderService aiChargeRefundOrderService;
|
||||
|
||||
/**
|
||||
* 查询团队(部门)充值退款订单列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('ai:order:list')")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(AiChargeRefundOrder aiChargeRefundOrder)
|
||||
{
|
||||
startPage();
|
||||
List<AiChargeRefundOrder> list = aiChargeRefundOrderService.selectAiChargeRefundOrderList(aiChargeRefundOrder);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出团队(部门)充值退款订单列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('ai:order:export')")
|
||||
@Log(title = "团队(部门)充值退款订单", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(HttpServletResponse response, AiChargeRefundOrder aiChargeRefundOrder)
|
||||
{
|
||||
List<AiChargeRefundOrder> list = aiChargeRefundOrderService.selectAiChargeRefundOrderList(aiChargeRefundOrder);
|
||||
ExcelUtil<AiChargeRefundOrder> util = new ExcelUtil<AiChargeRefundOrder>(AiChargeRefundOrder.class);
|
||||
util.exportExcel(response, list, "团队(部门)充值退款订单数据");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取团队(部门)充值退款订单详细信息
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('ai:order:query')")
|
||||
@GetMapping(value = "/{id}")
|
||||
public AjaxResult getInfo(@PathVariable("id") Long id)
|
||||
{
|
||||
return success(aiChargeRefundOrderService.selectAiChargeRefundOrderById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增团队(部门)充值退款订单
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('ai:order:add')")
|
||||
@Log(title = "团队(部门)充值退款订单", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public AjaxResult add(@RequestBody AiChargeRefundOrder aiChargeRefundOrder)
|
||||
{
|
||||
return toAjax(aiChargeRefundOrderService.insertAiChargeRefundOrder(aiChargeRefundOrder));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改团队(部门)充值退款订单
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('ai:order:edit')")
|
||||
@Log(title = "团队(部门)充值退款订单", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public AjaxResult edit(@RequestBody AiChargeRefundOrder aiChargeRefundOrder)
|
||||
{
|
||||
return toAjax(aiChargeRefundOrderService.updateAiChargeRefundOrder(aiChargeRefundOrder));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除团队(部门)充值退款订单
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('ai:order:remove')")
|
||||
@Log(title = "团队(部门)充值退款订单", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public AjaxResult remove(@PathVariable Long[] ids)
|
||||
{
|
||||
return toAjax(aiChargeRefundOrderService.deleteAiChargeRefundOrderByIds(ids));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
package com.ruoyi.ai.controller;
|
||||
|
||||
import java.util.List;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.ai.domain.AiDeptArkConfig;
|
||||
import com.ruoyi.ai.service.IAiDeptArkConfigService;
|
||||
import com.ruoyi.common.utils.poi.ExcelUtil;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
|
||||
/**
|
||||
* 团队(部门)对应火山引擎配置Controller
|
||||
*
|
||||
* @author shi
|
||||
* @date 2026-04-17
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/ai/config")
|
||||
public class AiDeptArkConfigController extends BaseController
|
||||
{
|
||||
@Autowired
|
||||
private IAiDeptArkConfigService aiDeptArkConfigService;
|
||||
|
||||
/**
|
||||
* 查询团队(部门)对应火山引擎配置列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('ai:config:list')")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(AiDeptArkConfig aiDeptArkConfig)
|
||||
{
|
||||
startPage();
|
||||
List<AiDeptArkConfig> list = aiDeptArkConfigService.selectAiDeptArkConfigList(aiDeptArkConfig);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出团队(部门)对应火山引擎配置列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('ai:config:export')")
|
||||
@Log(title = "团队(部门)对应火山引擎配置", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(HttpServletResponse response, AiDeptArkConfig aiDeptArkConfig)
|
||||
{
|
||||
List<AiDeptArkConfig> list = aiDeptArkConfigService.selectAiDeptArkConfigList(aiDeptArkConfig);
|
||||
ExcelUtil<AiDeptArkConfig> util = new ExcelUtil<AiDeptArkConfig>(AiDeptArkConfig.class);
|
||||
util.exportExcel(response, list, "团队(部门)对应火山引擎配置数据");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取团队(部门)对应火山引擎配置详细信息
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('ai:config:query')")
|
||||
@GetMapping(value = "/{id}")
|
||||
public AjaxResult getInfo(@PathVariable("id") String id)
|
||||
{
|
||||
return success(aiDeptArkConfigService.selectAiDeptArkConfigById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增团队(部门)对应火山引擎配置
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('ai:config:add')")
|
||||
@Log(title = "团队(部门)对应火山引擎配置", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public AjaxResult add(@RequestBody AiDeptArkConfig aiDeptArkConfig)
|
||||
{
|
||||
return toAjax(aiDeptArkConfigService.insertAiDeptArkConfig(aiDeptArkConfig));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改团队(部门)对应火山引擎配置
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('ai:config:edit')")
|
||||
@Log(title = "团队(部门)对应火山引擎配置", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public AjaxResult edit(@RequestBody AiDeptArkConfig aiDeptArkConfig)
|
||||
{
|
||||
return toAjax(aiDeptArkConfigService.updateAiDeptArkConfig(aiDeptArkConfig));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除团队(部门)对应火山引擎配置
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('ai:config:remove')")
|
||||
@Log(title = "团队(部门)对应火山引擎配置", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public AjaxResult remove(@PathVariable String[] ids)
|
||||
{
|
||||
return toAjax(aiDeptArkConfigService.deleteAiDeptArkConfigByIds(ids));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
package com.ruoyi.ai.controller;
|
||||
|
||||
import java.util.List;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.ai.domain.AiGroupBalanceChangeRecord;
|
||||
import com.ruoyi.ai.service.IAiGroupBalanceChangeRecordService;
|
||||
import com.ruoyi.common.utils.poi.ExcelUtil;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
|
||||
/**
|
||||
* 团队(部门)余额变动Controller
|
||||
*
|
||||
* @author shi
|
||||
* @date 2026-04-17
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/ai/record")
|
||||
public class AiGroupBalanceChangeRecordController extends BaseController
|
||||
{
|
||||
@Autowired
|
||||
private IAiGroupBalanceChangeRecordService aiGroupBalanceChangeRecordService;
|
||||
|
||||
/**
|
||||
* 查询团队(部门)余额变动列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('ai:record:list')")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(AiGroupBalanceChangeRecord aiGroupBalanceChangeRecord)
|
||||
{
|
||||
startPage();
|
||||
List<AiGroupBalanceChangeRecord> list = aiGroupBalanceChangeRecordService.selectAiGroupBalanceChangeRecordList(aiGroupBalanceChangeRecord);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出团队(部门)余额变动列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('ai:record:export')")
|
||||
@Log(title = "团队(部门)余额变动", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(HttpServletResponse response, AiGroupBalanceChangeRecord aiGroupBalanceChangeRecord)
|
||||
{
|
||||
List<AiGroupBalanceChangeRecord> list = aiGroupBalanceChangeRecordService.selectAiGroupBalanceChangeRecordList(aiGroupBalanceChangeRecord);
|
||||
ExcelUtil<AiGroupBalanceChangeRecord> util = new ExcelUtil<AiGroupBalanceChangeRecord>(AiGroupBalanceChangeRecord.class);
|
||||
util.exportExcel(response, list, "团队(部门)余额变动数据");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取团队(部门)余额变动详细信息
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('ai:record:query')")
|
||||
@GetMapping(value = "/{id}")
|
||||
public AjaxResult getInfo(@PathVariable("id") String id)
|
||||
{
|
||||
return success(aiGroupBalanceChangeRecordService.selectAiGroupBalanceChangeRecordById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增团队(部门)余额变动
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('ai:record:add')")
|
||||
@Log(title = "团队(部门)余额变动", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public AjaxResult add(@RequestBody AiGroupBalanceChangeRecord aiGroupBalanceChangeRecord)
|
||||
{
|
||||
return toAjax(aiGroupBalanceChangeRecordService.insertAiGroupBalanceChangeRecord(aiGroupBalanceChangeRecord));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改团队(部门)余额变动
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('ai:record:edit')")
|
||||
@Log(title = "团队(部门)余额变动", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public AjaxResult edit(@RequestBody AiGroupBalanceChangeRecord aiGroupBalanceChangeRecord)
|
||||
{
|
||||
return toAjax(aiGroupBalanceChangeRecordService.updateAiGroupBalanceChangeRecord(aiGroupBalanceChangeRecord));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除团队(部门)余额变动
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('ai:record:remove')")
|
||||
@Log(title = "团队(部门)余额变动", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public AjaxResult remove(@PathVariable String[] ids)
|
||||
{
|
||||
return toAjax(aiGroupBalanceChangeRecordService.deleteAiGroupBalanceChangeRecordByIds(ids));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
package com.ruoyi.ai.controller;
|
||||
|
||||
import java.util.List;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.ai.domain.AiVideoReportData;
|
||||
import com.ruoyi.ai.service.IAiVideoReportDataService;
|
||||
import com.ruoyi.common.utils.poi.ExcelUtil;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
|
||||
/**
|
||||
* AI视频生成统计数据,作为其他统计报的数据源Controller
|
||||
*
|
||||
* @author shi
|
||||
* @date 2026-04-17
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/ai/data")
|
||||
public class AiVideoReportDataController extends BaseController
|
||||
{
|
||||
@Autowired
|
||||
private IAiVideoReportDataService aiVideoReportDataService;
|
||||
|
||||
/**
|
||||
* 查询AI视频生成统计数据,作为其他统计报的数据源列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('ai:data:list')")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(AiVideoReportData aiVideoReportData)
|
||||
{
|
||||
if (StringUtils.isEmpty(aiVideoReportData.getStatDate()) || aiVideoReportData.getDeptId() == null)
|
||||
{
|
||||
return getDataTable(java.util.Collections.emptyList());
|
||||
}
|
||||
startPage();
|
||||
List<AiVideoReportData> list = aiVideoReportDataService.selectTeamDailyConsumeList(
|
||||
aiVideoReportData.getStatDate(), aiVideoReportData.getDeptId());
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出AI视频生成统计数据,作为其他统计报的数据源列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('ai:data:export')")
|
||||
@Log(title = "AI视频生成统计数据,作为其他统计报的数据源", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(HttpServletResponse response, AiVideoReportData aiVideoReportData)
|
||||
{
|
||||
List<AiVideoReportData> list = aiVideoReportDataService.selectAiVideoReportDataList(aiVideoReportData);
|
||||
ExcelUtil<AiVideoReportData> util = new ExcelUtil<AiVideoReportData>(AiVideoReportData.class);
|
||||
util.exportExcel(response, list, "AI视频生成统计数据,作为其他统计报的数据源数据");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取AI视频生成统计数据,作为其他统计报的数据源详细信息
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('ai:data:query')")
|
||||
@GetMapping(value = "/{id}")
|
||||
public AjaxResult getInfo(@PathVariable("id") String id)
|
||||
{
|
||||
return success(aiVideoReportDataService.selectAiVideoReportDataById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增AI视频生成统计数据,作为其他统计报的数据源
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('ai:data:add')")
|
||||
@Log(title = "AI视频生成统计数据,作为其他统计报的数据源", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public AjaxResult add(@RequestBody AiVideoReportData aiVideoReportData)
|
||||
{
|
||||
return toAjax(aiVideoReportDataService.insertAiVideoReportData(aiVideoReportData));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改AI视频生成统计数据,作为其他统计报的数据源
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('ai:data:edit')")
|
||||
@Log(title = "AI视频生成统计数据,作为其他统计报的数据源", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public AjaxResult edit(@RequestBody AiVideoReportData aiVideoReportData)
|
||||
{
|
||||
return toAjax(aiVideoReportDataService.updateAiVideoReportData(aiVideoReportData));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除AI视频生成统计数据,作为其他统计报的数据源
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('ai:data:remove')")
|
||||
@Log(title = "AI视频生成统计数据,作为其他统计报的数据源", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public AjaxResult remove(@PathVariable String[] ids)
|
||||
{
|
||||
return toAjax(aiVideoReportDataService.deleteAiVideoReportDataByIds(ids));
|
||||
}
|
||||
}
|
||||
|
|
@ -162,7 +162,7 @@ public class PortalVideoController extends BaseController {
|
|||
List<PortalVideoProperties.ModelOption> allowed = loadModelOptionsForAiUser(uid, secondDeptId);
|
||||
String modelId = StringUtils.isNotEmpty(req.getModel()) ? req.getModel() : resolveDefaultModelForAiUser(uid, secondDeptId, allowed);
|
||||
if (StringUtils.isEmpty(modelId)) {
|
||||
throw new ServiceException("未配置门户视频模型:请在后台为该用户所属二级部门配置 model_parm,或在 portal.video.models 中配置全局列表");
|
||||
throw new ServiceException("未配置门户视频模型:请在后台为该用户所属二级部门配置");
|
||||
}
|
||||
if (StringUtils.isNotEmpty(req.getModel()) && !isModelInOptions(modelId, allowed)) {
|
||||
throw new ServiceException("所选模型对当前部门不可用");
|
||||
|
|
@ -517,7 +517,7 @@ public class PortalVideoController extends BaseController {
|
|||
}
|
||||
|
||||
@GetMapping("/options")
|
||||
@ApiOperation("门户视频生成可选参数(模型/比例/时长等,来自配置)")
|
||||
@ApiOperation("门户视频生成可选参数(模型/比例/时长等,来自系统参数)")
|
||||
public AjaxResult videoParamOptions() {
|
||||
Long uid = SecurityUtils.getAiUserId();
|
||||
Long secondDeptId = byteDeptApiKeyService.resolveSecondLevelDeptId(uid);
|
||||
|
|
|
|||
|
|
@ -1,115 +1,102 @@
|
|||
package com.ruoyi.config;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.system.service.ISysConfigService;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 门户视频生成参数(模型、比例、时长、分辨率等从配置读取,不在代码中写死业务默认值)。
|
||||
* 门户视频生成参数(从 sys_config 读取)。
|
||||
*/
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "portal.video")
|
||||
public class PortalVideoProperties {
|
||||
|
||||
private Defaults defaults = new Defaults();
|
||||
private static final ObjectMapper OM = new ObjectMapper();
|
||||
|
||||
private List<ModelOption> models = new ArrayList<>();
|
||||
/** 默认值:{"model":"...","duration":5,"resolution":"720p","ratio":"16:9"} */
|
||||
private static final String CFG_DEFAULTS = "portal.video.defaults";
|
||||
/** 模型列表:[{"label":"Seedance 2.0","value":"ep-xxx"}] */
|
||||
private static final String CFG_MODELS = "portal.video.models";
|
||||
/** 二级部门模型映射:{"101":[{"label":"...","value":"..."}]} */
|
||||
private static final String CFG_MODELS_BY_SECOND_DEPT = "portal.video.modelsBySecondDept";
|
||||
/** 二级部门默认值覆盖:{"101":{"duration":5,"resolution":"720p"}} */
|
||||
private static final String CFG_DEFAULTS_BY_SECOND_DEPT = "portal.video.defaultsBySecondDept";
|
||||
/** 比例列表:["16:9","9:16"] */
|
||||
private static final String CFG_RATIOS = "portal.video.ratios";
|
||||
/** 时长列表:[5,10] */
|
||||
private static final String CFG_DURATIONS = "portal.video.durations";
|
||||
/** 分辨率列表:["720p","1080p"] */
|
||||
private static final String CFG_RESOLUTIONS = "portal.video.resolutions";
|
||||
/** 功能类型:与 ai_manager.type 对应 */
|
||||
private static final String CFG_FUNCTION_TYPE = "portal.video.functionType";
|
||||
private static final String DEFAULT_FUNCTION_TYPE = "21";
|
||||
|
||||
/**
|
||||
* 按二级部门 {@code dept_id}(字符串,如 {@code "101"})配置专属模型列表;未命中时使用全局 {@link #models}。
|
||||
*/
|
||||
private Map<String, List<ModelOption>> modelsBySecondDept = new LinkedHashMap<>();
|
||||
|
||||
/**
|
||||
* 按二级部门覆盖 {@link #defaults} 中的字段;仅配置需要覆盖的项即可。
|
||||
*/
|
||||
private Map<String, Defaults> defaultsBySecondDept = new LinkedHashMap<>();
|
||||
|
||||
private List<String> ratios = new ArrayList<>();
|
||||
|
||||
private List<Integer> durations = new ArrayList<>();
|
||||
|
||||
private List<String> resolutions = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* 与 ai_manager.type 一致,用于扣费与订单;库中需存在对应记录且 status=0、del_flag=0
|
||||
*/
|
||||
private String functionType = "21";
|
||||
@Resource
|
||||
private ISysConfigService sysConfigService;
|
||||
|
||||
public String getFunctionType() {
|
||||
return functionType;
|
||||
}
|
||||
|
||||
public void setFunctionType(String functionType) {
|
||||
this.functionType = functionType != null ? functionType : "21";
|
||||
String functionType = trimToNull(sysConfigService.selectConfigByKey(CFG_FUNCTION_TYPE));
|
||||
return functionType != null ? functionType : DEFAULT_FUNCTION_TYPE;
|
||||
}
|
||||
|
||||
public Defaults getDefaults() {
|
||||
return defaults;
|
||||
}
|
||||
|
||||
public void setDefaults(Defaults defaults) {
|
||||
if (defaults != null) {
|
||||
this.defaults = defaults;
|
||||
}
|
||||
Defaults defaults = parseObjectConfig(CFG_DEFAULTS, Defaults.class);
|
||||
return defaults != null ? defaults : new Defaults();
|
||||
}
|
||||
|
||||
public List<ModelOption> getModels() {
|
||||
return models;
|
||||
}
|
||||
|
||||
public void setModels(List<ModelOption> models) {
|
||||
this.models = models != null ? models : new ArrayList<>();
|
||||
List<ModelOption> models = parseListConfig(CFG_MODELS, new TypeReference<List<ModelOption>>() {
|
||||
});
|
||||
return models != null ? models : new ArrayList<>();
|
||||
}
|
||||
|
||||
public Map<String, List<ModelOption>> getModelsBySecondDept() {
|
||||
return modelsBySecondDept;
|
||||
}
|
||||
|
||||
public void setModelsBySecondDept(Map<String, List<ModelOption>> modelsBySecondDept) {
|
||||
this.modelsBySecondDept = modelsBySecondDept != null ? modelsBySecondDept : new LinkedHashMap<>();
|
||||
Map<String, List<ModelOption>> map = parseObjectConfig(CFG_MODELS_BY_SECOND_DEPT,
|
||||
new TypeReference<Map<String, List<ModelOption>>>() {
|
||||
});
|
||||
return map != null ? map : new LinkedHashMap<>();
|
||||
}
|
||||
|
||||
public Map<String, Defaults> getDefaultsBySecondDept() {
|
||||
return defaultsBySecondDept;
|
||||
}
|
||||
|
||||
public void setDefaultsBySecondDept(Map<String, Defaults> defaultsBySecondDept) {
|
||||
this.defaultsBySecondDept = defaultsBySecondDept != null ? defaultsBySecondDept : new LinkedHashMap<>();
|
||||
Map<String, Defaults> map = parseObjectConfig(CFG_DEFAULTS_BY_SECOND_DEPT,
|
||||
new TypeReference<Map<String, Defaults>>() {
|
||||
});
|
||||
return map != null ? map : new LinkedHashMap<>();
|
||||
}
|
||||
|
||||
public List<String> getRatios() {
|
||||
return ratios;
|
||||
}
|
||||
|
||||
public void setRatios(List<String> ratios) {
|
||||
this.ratios = ratios != null ? ratios : new ArrayList<>();
|
||||
List<String> ratios = parseListConfig(CFG_RATIOS, new TypeReference<List<String>>() {
|
||||
});
|
||||
return ratios != null ? ratios : Collections.emptyList();
|
||||
}
|
||||
|
||||
public List<Integer> getDurations() {
|
||||
return durations;
|
||||
}
|
||||
|
||||
public void setDurations(List<Integer> durations) {
|
||||
this.durations = durations != null ? durations : new ArrayList<>();
|
||||
List<Integer> durations = parseListConfig(CFG_DURATIONS, new TypeReference<List<Integer>>() {
|
||||
});
|
||||
return durations != null ? durations : Collections.emptyList();
|
||||
}
|
||||
|
||||
public List<String> getResolutions() {
|
||||
return resolutions;
|
||||
}
|
||||
|
||||
public void setResolutions(List<String> resolutions) {
|
||||
this.resolutions = resolutions != null ? resolutions : new ArrayList<>();
|
||||
List<String> resolutions = parseListConfig(CFG_RESOLUTIONS, new TypeReference<List<String>>() {
|
||||
});
|
||||
return resolutions != null ? resolutions : Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* defaults.model 为空时,取 models 第一项的 value。
|
||||
*/
|
||||
public String resolveDefaultModelId() {
|
||||
Defaults defaults = getDefaults();
|
||||
List<ModelOption> models = getModels();
|
||||
if (defaults.getModel() != null && !defaults.getModel().isEmpty()) {
|
||||
return defaults.getModel();
|
||||
}
|
||||
|
|
@ -120,6 +107,8 @@ public class PortalVideoProperties {
|
|||
}
|
||||
|
||||
public List<ModelOption> resolveModelsForSecondDept(Long secondDeptId) {
|
||||
Map<String, List<ModelOption>> modelsBySecondDept = getModelsBySecondDept();
|
||||
List<ModelOption> models = getModels();
|
||||
if (secondDeptId != null) {
|
||||
List<ModelOption> byDept = modelsBySecondDept.get(String.valueOf(secondDeptId));
|
||||
if (byDept != null && !byDept.isEmpty()) {
|
||||
|
|
@ -131,12 +120,13 @@ public class PortalVideoProperties {
|
|||
|
||||
public Defaults resolveEffectiveDefaults(Long secondDeptId) {
|
||||
Defaults out = new Defaults();
|
||||
Defaults g = this.defaults;
|
||||
Defaults g = this.getDefaults();
|
||||
out.setModel(g.getModel());
|
||||
out.setDuration(g.getDuration());
|
||||
out.setResolution(g.getResolution());
|
||||
out.setRatio(g.getRatio());
|
||||
if (secondDeptId != null) {
|
||||
Map<String, Defaults> defaultsBySecondDept = getDefaultsBySecondDept();
|
||||
Defaults o = defaultsBySecondDept.get(String.valueOf(secondDeptId));
|
||||
if (o != null) {
|
||||
if (o.getModel() != null && !o.getModel().isEmpty()) {
|
||||
|
|
@ -183,6 +173,51 @@ public class PortalVideoProperties {
|
|||
return false;
|
||||
}
|
||||
|
||||
private <T> T parseObjectConfig(String key, Class<T> clazz) {
|
||||
String raw = trimToNull(sysConfigService.selectConfigByKey(key));
|
||||
if (raw == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return OM.readValue(raw, clazz);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private <T> T parseObjectConfig(String key, TypeReference<T> typeReference) {
|
||||
String raw = trimToNull(sysConfigService.selectConfigByKey(key));
|
||||
if (raw == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return OM.readValue(raw, typeReference);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private <T> List<T> parseListConfig(String key, TypeReference<List<T>> typeReference) {
|
||||
String raw = trimToNull(sysConfigService.selectConfigByKey(key));
|
||||
if (raw == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
List<T> list = OM.readValue(raw, typeReference);
|
||||
return list != null ? list : new ArrayList<>();
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private String trimToNull(String value) {
|
||||
if (StringUtils.isEmpty(value)) {
|
||||
return null;
|
||||
}
|
||||
String out = value.trim();
|
||||
return out.isEmpty() ? null : out;
|
||||
}
|
||||
|
||||
public static class Defaults {
|
||||
private String model;
|
||||
private Integer duration;
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ import java.util.List;
|
|||
* @date 2025-11-13
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/ai/order")
|
||||
@RequestMapping("/ai/video/order")
|
||||
public class AiOrderController extends BaseController
|
||||
{
|
||||
@Autowired
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
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.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.domain.entity.AiUser;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.ai.service.IAiUserService;
|
||||
import com.ruoyi.system.service.subteam.ISubteamScopeService;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/subteam/user")
|
||||
public class SubteamUserController extends BaseController {
|
||||
|
||||
@Autowired
|
||||
private IAiUserService aiUserService;
|
||||
|
||||
@Autowired
|
||||
private ISubteamScopeService subteamScopeService;
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('subteam:user:list')")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(AiUser aiUser) {
|
||||
aiUser.setDeptId(subteamScopeService.currentTeamDeptId());
|
||||
startPage();
|
||||
List<AiUser> list = aiUserService.selectAiUserList(aiUser);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('subteam:user:query')")
|
||||
@GetMapping(value = {"/", "/{userId}"})
|
||||
public AjaxResult getInfo(@PathVariable(value = "userId", required = false) Long userId) {
|
||||
if (StringUtils.isNotNull(userId)) {
|
||||
subteamScopeService.assertAiUserInTeam(userId);
|
||||
return success(aiUserService.selectAiUserById(userId));
|
||||
}
|
||||
return success();
|
||||
}
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('subteam:user:add')")
|
||||
@Log(title = "团队后台用户", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public AjaxResult add(@Validated @RequestBody AiUser aiUser) {
|
||||
if (StringUtils.isEmpty(aiUser.getUsername())) {
|
||||
return error("登录账号不能为空");
|
||||
}
|
||||
if (StringUtils.isEmpty(aiUser.getPassword())) {
|
||||
return error("密码不能为空");
|
||||
}
|
||||
aiUser.setDeptId(subteamScopeService.currentTeamDeptId());
|
||||
aiUser.setCreateBy(getUsername());
|
||||
return toAjax(aiUserService.insertAiUser(aiUser));
|
||||
}
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('subteam:user:edit')")
|
||||
@Log(title = "团队后台用户", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public AjaxResult edit(@Validated @RequestBody AiUser aiUser) {
|
||||
if (aiUser.getId() == null) {
|
||||
return error("用户主键不能为空");
|
||||
}
|
||||
subteamScopeService.assertAiUserInTeam(aiUser.getId());
|
||||
aiUser.setDeptId(subteamScopeService.currentTeamDeptId());
|
||||
aiUser.setUpdateBy(getUsername());
|
||||
return toAjax(aiUserService.updateAiUser(aiUser));
|
||||
}
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('subteam:user:remove')")
|
||||
@Log(title = "团队后台用户", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{userIds}")
|
||||
public AjaxResult remove(@PathVariable Long[] userIds) {
|
||||
for (Long userId : userIds) {
|
||||
subteamScopeService.assertAiUserInTeam(userId);
|
||||
}
|
||||
return toAjax(aiUserService.deleteAiUserByIds(userIds));
|
||||
}
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('subteam:user:resetPwd')")
|
||||
@Log(title = "团队后台用户", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/resetPwd")
|
||||
public AjaxResult resetPwd(@RequestBody AiUser aiUser) {
|
||||
if (aiUser.getId() == null) {
|
||||
return error("用户主键不能为空");
|
||||
}
|
||||
if (StringUtils.isEmpty(aiUser.getPassword())) {
|
||||
return error("新密码不能为空");
|
||||
}
|
||||
subteamScopeService.assertAiUserInTeam(aiUser.getId());
|
||||
aiUser.setNewPassword(aiUser.getPassword());
|
||||
return toAjax(aiUserService.updatePassword(aiUser));
|
||||
}
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('subteam:user:edit')")
|
||||
@Log(title = "团队后台用户", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/changeStatus")
|
||||
public AjaxResult changeStatus(@RequestBody AiUser aiUser) {
|
||||
if (aiUser.getId() == null) {
|
||||
return error("用户主键不能为空");
|
||||
}
|
||||
subteamScopeService.assertAiUserInTeam(aiUser.getId());
|
||||
aiUser.setUpdateBy(getUsername());
|
||||
return toAjax(aiUserService.updateUserStatus(aiUser));
|
||||
}
|
||||
}
|
||||
|
|
@ -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.AiOrder;
|
||||
import com.ruoyi.ai.service.IAiOrderService;
|
||||
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/video-order")
|
||||
public class SubteamVideoOrderController extends BaseController {
|
||||
|
||||
@Autowired
|
||||
private ISubteamDataQueryService subteamDataQueryService;
|
||||
|
||||
@Autowired
|
||||
private ISubteamScopeService subteamScopeService;
|
||||
|
||||
@Autowired
|
||||
private IAiOrderService aiOrderService;
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('subteam:videoOrder:list')")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(AiOrder query) {
|
||||
startPage();
|
||||
List<AiOrder> list = subteamDataQueryService.selectVideoOrders(query);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('subteam:videoOrder:query')")
|
||||
@GetMapping("/{id}")
|
||||
public AjaxResult getInfo(@PathVariable Long id) {
|
||||
subteamScopeService.assertAiOrderBelongsToTeam(id);
|
||||
return success(aiOrderService.selectAiOrderById(id));
|
||||
}
|
||||
}
|
||||
|
|
@ -74,20 +74,13 @@ public class BalanceChangerConstants {
|
|||
public static final int SYSTEM_OPERATION = 11;
|
||||
|
||||
/**
|
||||
* 部门积分下放至用户(sys_dept.balance → ai_user.balance)
|
||||
* 部门下发积分给用户
|
||||
*/
|
||||
public static final int DEPT_SCORE_ISSUE = 12;
|
||||
|
||||
/**
|
||||
* 用户积分回收至部门(ai_user.balance → sys_dept.balance)
|
||||
* 从用户回收积分到部门
|
||||
*/
|
||||
public static final int DEPT_SCORE_RECLAIM = 13;
|
||||
|
||||
public static class OrderNoPrefix {
|
||||
// 团队充值、退款订单号前缀
|
||||
public static final String RECHARGE_REFUND_PREFIX = "RE";
|
||||
|
||||
// 团队积分下放、回收单号前缀
|
||||
public static final String ISSUE_RECLAIM_PREFIX = "IS";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
<el-form-item label="${comment}" prop="${column.javaField}">
|
||||
<el-input
|
||||
v-model="queryParams.${column.javaField}"
|
||||
placeholder="请输入${comment}"
|
||||
placeholder="请输入ID"
|
||||
clearable
|
||||
@keyup.enter="handleQuery"
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -1,56 +1,67 @@
|
|||
package com.ruoyi.ai.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.ruoyi.common.annotation.Excel;
|
||||
import java.math.BigDecimal;
|
||||
import lombok.Data;
|
||||
import com.ruoyi.common.annotation.Excel;
|
||||
import com.ruoyi.common.core.domain.BaseEntity;
|
||||
|
||||
/**
|
||||
* 充值/退款订单 ai_charge_refund_order
|
||||
* 团队(部门)充值退款订单对象 ai_charge_refund_order
|
||||
*
|
||||
* @author shi
|
||||
* @date 2026-04-17
|
||||
*/
|
||||
@Data
|
||||
@TableName("ai_charge_refund_order")
|
||||
public class AiChargeRefundOrder implements Serializable {
|
||||
public class AiChargeRefundOrder extends BaseEntity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 主键ID */
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/** 删除标志(0代表存在 2代表删除) */
|
||||
private String delFlag;
|
||||
|
||||
private Long createBy;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date createTime;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date updateTime;
|
||||
|
||||
/** 订单编号 */
|
||||
@Excel(name = "订单编号")
|
||||
private String orderNum;
|
||||
|
||||
/** 第三方单号(预留) */
|
||||
@Excel(name = "第三方单号(预留)")
|
||||
private String thirdPartyOrderNum;
|
||||
|
||||
/** 部门ID */
|
||||
@Excel(name = "部门ID")
|
||||
private Long deptId;
|
||||
|
||||
/** 订单类型:0-充值 1-退款 */
|
||||
// ChargeRefundOrderType
|
||||
private Integer orderType;
|
||||
/** 团队名称(列表/导出关联查询,非表字段) */
|
||||
@TableField(exist = false)
|
||||
@Excel(name = "团队名称")
|
||||
private String deptName;
|
||||
|
||||
/** 订单类型(0-充值;1-退款;2-手动修改) */
|
||||
@Excel(name = "订单类型", readConverterExp = "0=充值,1=退款,2=手动修改")
|
||||
private Long orderType;
|
||||
|
||||
/** 金额(元) */
|
||||
@Excel(name = "金额(元)")
|
||||
private BigDecimal money;
|
||||
|
||||
/**
|
||||
* 积分变动:充值/退款为绝对值(退款在统计中按负数计入);
|
||||
* 手动修改可为正(增加)或负(扣减)。
|
||||
*/
|
||||
@Excel(name = "积分")
|
||||
private BigDecimal amount;
|
||||
|
||||
private String remark;
|
||||
|
||||
/** 状态:0-进行中 1-已完成 2-失败 */
|
||||
// ChargeRefundOrderStatusType
|
||||
@Excel(name = "状态", readConverterExp = "0=进行中,1=已完成,2=失败")
|
||||
private Integer status;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,42 +1,44 @@
|
|||
package com.ruoyi.ai.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Data;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
import com.ruoyi.common.annotation.Excel;
|
||||
import com.ruoyi.common.core.domain.BaseEntity;
|
||||
|
||||
/**
|
||||
* 部门方舟配置 ai_dept_ark_config
|
||||
* 团队(部门)对应火山引擎配置对象 ai_dept_ark_config
|
||||
*
|
||||
* @author shi
|
||||
* @date 2026-04-17
|
||||
*/
|
||||
@Data
|
||||
@TableName("ai_dept_ark_config")
|
||||
public class AiDeptArkConfig implements Serializable {
|
||||
public class AiDeptArkConfig extends BaseEntity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** $column.columnComment */
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
private String id;
|
||||
|
||||
/** 部门ID */
|
||||
@Excel(name = "部门ID")
|
||||
private Long deptId;
|
||||
|
||||
/** 模型参数 JSON */
|
||||
/** 视频模型列表JSON(label+value) */
|
||||
@Excel(name = "视频模型列表JSON(label+value)")
|
||||
private String modelParm;
|
||||
|
||||
/** Byte project,加密 */
|
||||
@Excel(name = "Byte project,加密")
|
||||
private String project;
|
||||
|
||||
/** Byte API Key,加密 */
|
||||
@Excel(name = "Byte API Key,加密")
|
||||
private String byteApiKey;
|
||||
|
||||
private Long createBy;
|
||||
|
||||
private Long updateBy;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date createTime;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date updateTime;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,49 +1,49 @@
|
|||
package com.ruoyi.ai.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.EnumValue;
|
||||
import lombok.Data;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.ruoyi.common.annotation.Excel;
|
||||
import lombok.Data;
|
||||
import com.ruoyi.common.core.domain.BaseEntity;
|
||||
|
||||
/**
|
||||
* 集团余额变动记录 ai_group_balance_change_record
|
||||
* 团队(部门)余额变动对象 ai_group_balance_change_record
|
||||
*
|
||||
* @author shi
|
||||
* @date 2026-04-17
|
||||
*/
|
||||
@Data
|
||||
@TableName("ai_group_balance_change_record")
|
||||
public class AiGroupBalanceChangeRecord implements Serializable {
|
||||
public class AiGroupBalanceChangeRecord extends BaseEntity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** $column.columnComment */
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
private String id;
|
||||
|
||||
/** 关联订单号 */
|
||||
/** 关联(充值/退款)订单号 */
|
||||
@Excel(name = "关联(充值/退款)订单号")
|
||||
private String relationOrderNo;
|
||||
|
||||
/** 部门ID */
|
||||
@Excel(name = "部门ID")
|
||||
private Long deptId;
|
||||
|
||||
/** 类型:0-充值 1-退款 2-下发 3-消费 4-手动修改 */
|
||||
// GroupBalanceChangeType
|
||||
private Integer type;
|
||||
/** 操作类型(0-充值、1-退款、2-下发、3-回收、4-手动修改) */
|
||||
@Excel(name = "操作类型", readConverterExp = "0=-充值、1-退款、2-下发、3-回收、4-手动修改")
|
||||
private Long type;
|
||||
|
||||
/** 变更金额 */
|
||||
@Excel(name = "变更金额")
|
||||
private BigDecimal changeAmount;
|
||||
|
||||
/** 变更后金额 */
|
||||
@Excel(name = "变更后金额")
|
||||
private BigDecimal resultAmount;
|
||||
|
||||
private String remark;
|
||||
|
||||
private Long createBy;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date createTime;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date updateTime;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,50 +1,63 @@
|
|||
package com.ruoyi.ai.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.ruoyi.common.annotation.Excel;
|
||||
import java.math.BigDecimal;
|
||||
import lombok.Data;
|
||||
import com.ruoyi.common.annotation.Excel;
|
||||
import com.ruoyi.common.core.domain.BaseEntity;
|
||||
|
||||
/**
|
||||
* 视频报表数据 ai_video_report_data
|
||||
* AI视频生成统计数据,作为其他统计报的数据源对象 ai_video_report_data
|
||||
*
|
||||
* @author shi
|
||||
* @date 2026-04-17
|
||||
*/
|
||||
@Data
|
||||
@TableName("ai_video_report_data")
|
||||
public class AiVideoReportData implements Serializable {
|
||||
public class AiVideoReportData extends BaseEntity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 主键 */
|
||||
/** $column.columnComment */
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
private String id;
|
||||
|
||||
/** 统计日期键(varchar) */
|
||||
/** 统计时间,到小时(yyyyMMddHH) */
|
||||
@Excel(name = "统计时间,到小时('%Y-%m-%d %H')")
|
||||
private String dateKey;
|
||||
|
||||
/** 部门ID */
|
||||
@Excel(name = "部门ID")
|
||||
private Long deptId;
|
||||
|
||||
/** 用户ID */
|
||||
/** 用户ID,用户表的ID,延用其他表设计 */
|
||||
@Excel(name = "用户ID,用户表的ID,延用其他表设计 ")
|
||||
private Long userId;
|
||||
|
||||
/** 积分/分数统计 */
|
||||
/** 消耗积分,按任务创建时间统计 */
|
||||
@Excel(name = "消耗积分,按任务创建时间统计")
|
||||
private BigDecimal score;
|
||||
|
||||
/** 订单数 */
|
||||
/** 实际订单数,只统计已生成成功的任务 */
|
||||
@Excel(name = "实际订单数,只统计已生成成功的任务")
|
||||
private Long orderCount;
|
||||
|
||||
/** 消耗 tokens */
|
||||
/** 三方消耗tokens数量,按任务创建时间统计 */
|
||||
@Excel(name = "三方消耗tokens数量,按任务创建时间统计")
|
||||
private Long useTokens;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date createTime;
|
||||
/** 实际充值积分(充值-退款) */
|
||||
@Excel(name = "实际充值积分(充值-退款)")
|
||||
private BigDecimal rechargeScore;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date updateTime;
|
||||
/** 团队名称(查询结果展示字段) */
|
||||
@TableField(exist = false)
|
||||
private String deptName;
|
||||
|
||||
/** 查询日期(yyyyMMdd) */
|
||||
@TableField(exist = false)
|
||||
private String statDate;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import java.util.List;
|
|||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.ruoyi.ai.domain.AiBalanceChangeRecord;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
/**
|
||||
* 余额使用记录Mapper接口
|
||||
|
|
@ -17,4 +18,7 @@ public interface AiBalanceChangeRecordMapper extends BaseMapper<AiBalanceChangeR
|
|||
int deleteAiBalanceChangeRecordById(Long id);
|
||||
|
||||
List<AiBalanceChangeRecord> selectAiBalanceChangeRecordList(AiBalanceChangeRecord aiBalanceChangeRecord);
|
||||
|
||||
List<AiBalanceChangeRecord> selectAiBalanceChangeRecordListByAiUserDept(@Param("q") AiBalanceChangeRecord q,
|
||||
@Param("deptId") Long deptId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,24 @@
|
|||
package com.ruoyi.ai.mapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.ruoyi.ai.domain.AiChargeRefundOrder;
|
||||
|
||||
/**
|
||||
* 充值/退款订单 Mapper
|
||||
* 团队(部门)充值退款订单Mapper接口
|
||||
*
|
||||
* @author shi
|
||||
* @date 2026-04-17
|
||||
*/
|
||||
public interface AiChargeRefundOrderMapper extends BaseMapper<AiChargeRefundOrder> {
|
||||
|
||||
/**
|
||||
* 列表(关联团队名称,支持按 deptName 模糊查)
|
||||
*/
|
||||
List<AiChargeRefundOrder> selectAiChargeRefundOrderList(AiChargeRefundOrder query);
|
||||
|
||||
AiChargeRefundOrder selectAiChargeRefundOrderById(Long id);
|
||||
|
||||
int deleteAiChargeRefundOrderByIds(Long[] ids);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,15 @@
|
|||
package com.ruoyi.ai.mapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.ruoyi.ai.domain.AiDeptArkConfig;
|
||||
|
||||
/**
|
||||
* 部门方舟配置 Mapper
|
||||
* 团队(部门)对应火山引擎配置Mapper接口
|
||||
*
|
||||
* @author shi
|
||||
* @date 2026-04-17
|
||||
*/
|
||||
public interface AiDeptArkConfigMapper extends BaseMapper<AiDeptArkConfig> {
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,15 @@
|
|||
package com.ruoyi.ai.mapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.ruoyi.ai.domain.AiGroupBalanceChangeRecord;
|
||||
|
||||
/**
|
||||
* 集团余额变动记录 Mapper
|
||||
* 团队(部门)余额变动Mapper接口
|
||||
*
|
||||
* @author shi
|
||||
* @date 2026-04-17
|
||||
*/
|
||||
public interface AiGroupBalanceChangeRecordMapper extends BaseMapper<AiGroupBalanceChangeRecord> {
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,74 @@
|
|||
package com.ruoyi.ai.mapper;
|
||||
|
||||
import java.util.List;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.ruoyi.ai.domain.AiOrder;
|
||||
import com.ruoyi.ai.domain.AiVideoReportData;
|
||||
import com.ruoyi.common.core.dto.DeptSummaryDTO;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
import com.ruoyi.system.domain.subteam.SubteamVideoMetrics;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Update;
|
||||
|
||||
/**
|
||||
* 视频报表数据 Mapper
|
||||
* AI视频生成统计数据,作为其他统计报的数据源Mapper接口
|
||||
*
|
||||
* @author shi
|
||||
* @date 2026-04-17
|
||||
*/
|
||||
public interface AiVideoReportDataMapper extends BaseMapper<AiVideoReportData> {
|
||||
@Select("SELECT SUM(order_count) as order_count,SUM(score) as score FROM ai_video_report_data " +
|
||||
" where dept_id=#{deptId} and date_key>=#{startHour} and date_key<=#{endHour}")
|
||||
DeptSummaryDTO selectOneDeptSummaryData(Long deptId, String startHour, String endHour);
|
||||
/**
|
||||
* 团队每日消耗统计查询(按天、团队聚合)。
|
||||
*
|
||||
* @param statDate 统计日期(yyyyMMdd)
|
||||
* @param deptId 团队部门ID(精确匹配)
|
||||
* @return 聚合结果
|
||||
*/
|
||||
List<AiVideoReportData> selectTeamDailyConsumeList(@Param("statDate") String statDate,
|
||||
@Param("deptId") Long deptId);
|
||||
|
||||
/**
|
||||
* 按团队部门、日期聚合(团队后台消耗统计)
|
||||
*/
|
||||
List<AiVideoReportData> selectTeamDailyConsumeByDeptId(@Param("statDate") String statDate,
|
||||
@Param("deptId") Long deptId);
|
||||
|
||||
/**
|
||||
* 近 N 日(含)按 date_key 日维度汇总消耗积分与成功订单数
|
||||
*/
|
||||
SubteamVideoMetrics selectDeptVideoMetricsBetween(@Param("deptId") Long deptId,
|
||||
@Param("startDay") String startDay,
|
||||
@Param("endDay") String endDay);
|
||||
|
||||
/**
|
||||
* 按(date_key, dept_id, user_id)聚合累加视频消耗统计。
|
||||
*
|
||||
* @param dateKey 小时Key(yyyyMMddHH)
|
||||
* @param deptId 部门ID
|
||||
* @param userId 用户ID
|
||||
* @param score 消耗积分增量
|
||||
* @param orderCount 订单数增量
|
||||
* @param useTokens 三方tokens增量
|
||||
* @return 影响行数
|
||||
*/
|
||||
int upsertVideoConsumeIncrement(@Param("dateKey") String dateKey,
|
||||
@Param("deptId") Long deptId,
|
||||
@Param("userId") Long userId,
|
||||
@Param("score") BigDecimal score,
|
||||
@Param("orderCount") Long orderCount,
|
||||
@Param("useTokens") Long useTokens);
|
||||
|
||||
/**
|
||||
* 按(date_key, dept_id, user_id=0)聚合累加充值积分统计。
|
||||
*
|
||||
* @param dateKey 小时Key(yyyyMMddHH)
|
||||
* @param deptId 部门ID
|
||||
* @param rechargeScore 充值积分增量
|
||||
* @return 影响行数
|
||||
*/
|
||||
int upsertRechargeScoreIncrement(@Param("dateKey") String dateKey,
|
||||
@Param("deptId") Long deptId,
|
||||
@Param("rechargeScore") BigDecimal rechargeScore);
|
||||
|
||||
void addNewOrderReportData(AiOrder aiOrder);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,71 @@
|
|||
package com.ruoyi.ai.service;
|
||||
|
||||
import java.util.List;
|
||||
import com.ruoyi.ai.domain.AiChargeRefundOrder;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
|
||||
/**
|
||||
* 充值/退款订单 Service
|
||||
* 团队(部门)充值退款订单Service接口
|
||||
*
|
||||
* @author shi
|
||||
* @date 2026-04-17
|
||||
*/
|
||||
public interface IAiChargeRefundOrderService {
|
||||
|
||||
AiChargeRefundOrder selectById(Long id);
|
||||
/**
|
||||
* 查询团队(部门)充值退款订单
|
||||
*
|
||||
* @param id 团队(部门)充值退款订单主键
|
||||
* @return 团队(部门)充值退款订单
|
||||
*/
|
||||
AiChargeRefundOrder selectAiChargeRefundOrderById(Long id);
|
||||
|
||||
int insert(AiChargeRefundOrder entity);
|
||||
/**
|
||||
* 查询团队(部门)充值退款订单列表
|
||||
*
|
||||
* @param aiChargeRefundOrder 团队(部门)充值退款订单
|
||||
* @return 团队(部门)充值退款订单集合
|
||||
*/
|
||||
List<AiChargeRefundOrder> selectAiChargeRefundOrderList(AiChargeRefundOrder aiChargeRefundOrder);
|
||||
|
||||
int updateById(AiChargeRefundOrder entity);
|
||||
/**
|
||||
* 分页查询团队(部门)充值退款订单列表
|
||||
*
|
||||
* @param aiChargeRefundOrder 团队(部门)充值退款订单
|
||||
* @return 团队(部门)充值退款订单集合
|
||||
*/
|
||||
IPage<AiChargeRefundOrder> selectAiChargeRefundOrderPage(Page page, AiChargeRefundOrder aiChargeRefundOrder);
|
||||
|
||||
int deleteById(Long id);
|
||||
/**
|
||||
* 新增团队(部门)充值退款订单
|
||||
*
|
||||
* @param aiChargeRefundOrder 团队(部门)充值退款订单
|
||||
* @return 结果
|
||||
*/
|
||||
int insertAiChargeRefundOrder(AiChargeRefundOrder aiChargeRefundOrder);
|
||||
|
||||
/**
|
||||
* 修改团队(部门)充值退款订单
|
||||
*
|
||||
* @param aiChargeRefundOrder 团队(部门)充值退款订单
|
||||
* @return 结果
|
||||
*/
|
||||
int updateAiChargeRefundOrder(AiChargeRefundOrder aiChargeRefundOrder);
|
||||
|
||||
/**
|
||||
* 批量删除团队(部门)充值退款订单
|
||||
*
|
||||
* @param ids 需要删除的团队(部门)充值退款订单主键集合
|
||||
* @return 结果
|
||||
*/
|
||||
int deleteAiChargeRefundOrderByIds(Long[] ids);
|
||||
|
||||
/**
|
||||
* 删除团队(部门)充值退款订单信息
|
||||
*
|
||||
* @param id 团队(部门)充值退款订单主键
|
||||
* @return 结果
|
||||
*/
|
||||
int deleteAiChargeRefundOrderById(Long id);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,71 @@
|
|||
package com.ruoyi.ai.service;
|
||||
|
||||
import java.util.List;
|
||||
import com.ruoyi.ai.domain.AiDeptArkConfig;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
|
||||
/**
|
||||
* 部门方舟配置 Service
|
||||
* 团队(部门)对应火山引擎配置Service接口
|
||||
*
|
||||
* @author shi
|
||||
* @date 2026-04-17
|
||||
*/
|
||||
public interface IAiDeptArkConfigService {
|
||||
|
||||
AiDeptArkConfig selectById(Long id);
|
||||
/**
|
||||
* 查询团队(部门)对应火山引擎配置
|
||||
*
|
||||
* @param id 团队(部门)对应火山引擎配置主键
|
||||
* @return 团队(部门)对应火山引擎配置
|
||||
*/
|
||||
AiDeptArkConfig selectAiDeptArkConfigById(String id);
|
||||
|
||||
int insert(AiDeptArkConfig entity);
|
||||
/**
|
||||
* 查询团队(部门)对应火山引擎配置列表
|
||||
*
|
||||
* @param aiDeptArkConfig 团队(部门)对应火山引擎配置
|
||||
* @return 团队(部门)对应火山引擎配置集合
|
||||
*/
|
||||
List<AiDeptArkConfig> selectAiDeptArkConfigList(AiDeptArkConfig aiDeptArkConfig);
|
||||
|
||||
int updateById(AiDeptArkConfig entity);
|
||||
/**
|
||||
* 分页查询团队(部门)对应火山引擎配置列表
|
||||
*
|
||||
* @param aiDeptArkConfig 团队(部门)对应火山引擎配置
|
||||
* @return 团队(部门)对应火山引擎配置集合
|
||||
*/
|
||||
IPage<AiDeptArkConfig> selectAiDeptArkConfigPage(Page page, AiDeptArkConfig aiDeptArkConfig);
|
||||
|
||||
int deleteById(Long id);
|
||||
/**
|
||||
* 新增团队(部门)对应火山引擎配置
|
||||
*
|
||||
* @param aiDeptArkConfig 团队(部门)对应火山引擎配置
|
||||
* @return 结果
|
||||
*/
|
||||
int insertAiDeptArkConfig(AiDeptArkConfig aiDeptArkConfig);
|
||||
|
||||
/**
|
||||
* 修改团队(部门)对应火山引擎配置
|
||||
*
|
||||
* @param aiDeptArkConfig 团队(部门)对应火山引擎配置
|
||||
* @return 结果
|
||||
*/
|
||||
int updateAiDeptArkConfig(AiDeptArkConfig aiDeptArkConfig);
|
||||
|
||||
/**
|
||||
* 批量删除团队(部门)对应火山引擎配置
|
||||
*
|
||||
* @param ids 需要删除的团队(部门)对应火山引擎配置主键集合
|
||||
* @return 结果
|
||||
*/
|
||||
int deleteAiDeptArkConfigByIds(String[] ids);
|
||||
|
||||
/**
|
||||
* 删除团队(部门)对应火山引擎配置信息
|
||||
*
|
||||
* @param id 团队(部门)对应火山引擎配置主键
|
||||
* @return 结果
|
||||
*/
|
||||
int deleteAiDeptArkConfigById(String id);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,71 @@
|
|||
package com.ruoyi.ai.service;
|
||||
|
||||
import java.util.List;
|
||||
import com.ruoyi.ai.domain.AiGroupBalanceChangeRecord;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
|
||||
/**
|
||||
* 集团余额变动记录 Service
|
||||
* 团队(部门)余额变动Service接口
|
||||
*
|
||||
* @author shi
|
||||
* @date 2026-04-17
|
||||
*/
|
||||
public interface IAiGroupBalanceChangeRecordService {
|
||||
|
||||
AiGroupBalanceChangeRecord selectById(Long id);
|
||||
/**
|
||||
* 查询团队(部门)余额变动
|
||||
*
|
||||
* @param id 团队(部门)余额变动主键
|
||||
* @return 团队(部门)余额变动
|
||||
*/
|
||||
AiGroupBalanceChangeRecord selectAiGroupBalanceChangeRecordById(String id);
|
||||
|
||||
int insert(AiGroupBalanceChangeRecord entity);
|
||||
/**
|
||||
* 查询团队(部门)余额变动列表
|
||||
*
|
||||
* @param aiGroupBalanceChangeRecord 团队(部门)余额变动
|
||||
* @return 团队(部门)余额变动集合
|
||||
*/
|
||||
List<AiGroupBalanceChangeRecord> selectAiGroupBalanceChangeRecordList(AiGroupBalanceChangeRecord aiGroupBalanceChangeRecord);
|
||||
|
||||
int updateById(AiGroupBalanceChangeRecord entity);
|
||||
/**
|
||||
* 分页查询团队(部门)余额变动列表
|
||||
*
|
||||
* @param aiGroupBalanceChangeRecord 团队(部门)余额变动
|
||||
* @return 团队(部门)余额变动集合
|
||||
*/
|
||||
IPage<AiGroupBalanceChangeRecord> selectAiGroupBalanceChangeRecordPage(Page page, AiGroupBalanceChangeRecord aiGroupBalanceChangeRecord);
|
||||
|
||||
int deleteById(Long id);
|
||||
/**
|
||||
* 新增团队(部门)余额变动
|
||||
*
|
||||
* @param aiGroupBalanceChangeRecord 团队(部门)余额变动
|
||||
* @return 结果
|
||||
*/
|
||||
int insertAiGroupBalanceChangeRecord(AiGroupBalanceChangeRecord aiGroupBalanceChangeRecord);
|
||||
|
||||
/**
|
||||
* 修改团队(部门)余额变动
|
||||
*
|
||||
* @param aiGroupBalanceChangeRecord 团队(部门)余额变动
|
||||
* @return 结果
|
||||
*/
|
||||
int updateAiGroupBalanceChangeRecord(AiGroupBalanceChangeRecord aiGroupBalanceChangeRecord);
|
||||
|
||||
/**
|
||||
* 批量删除团队(部门)余额变动
|
||||
*
|
||||
* @param ids 需要删除的团队(部门)余额变动主键集合
|
||||
* @return 结果
|
||||
*/
|
||||
int deleteAiGroupBalanceChangeRecordByIds(String[] ids);
|
||||
|
||||
/**
|
||||
* 删除团队(部门)余额变动信息
|
||||
*
|
||||
* @param id 团队(部门)余额变动主键
|
||||
* @return 结果
|
||||
*/
|
||||
int deleteAiGroupBalanceChangeRecordById(String id);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,107 @@
|
|||
package com.ruoyi.ai.service;
|
||||
|
||||
import com.ruoyi.ai.domain.AiVideoReportData;
|
||||
import com.ruoyi.common.core.dto.DeptSummaryDTO;
|
||||
|
||||
import java.util.List;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import com.ruoyi.ai.domain.AiVideoReportData;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
|
||||
/**
|
||||
* 视频报表数据 Service
|
||||
* AI视频生成统计数据,作为其他统计报的数据源Service接口
|
||||
*
|
||||
* @author shi
|
||||
* @date 2026-04-17
|
||||
*/
|
||||
public interface IAiVideoReportDataService {
|
||||
AiVideoReportData selectById(Long id);
|
||||
|
||||
int insert(AiVideoReportData entity);
|
||||
/**
|
||||
* 查询AI视频生成统计数据,作为其他统计报的数据源
|
||||
*
|
||||
* @param id AI视频生成统计数据,作为其他统计报的数据源主键
|
||||
* @return AI视频生成统计数据,作为其他统计报的数据源
|
||||
*/
|
||||
AiVideoReportData selectAiVideoReportDataById(String id);
|
||||
|
||||
DeptSummaryDTO getSevenDayDeptSummaryData(Long deptId);
|
||||
/**
|
||||
* 查询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 deptId 团队部门ID(必填,精确匹配)
|
||||
* @return 聚合后的统计数据
|
||||
*/
|
||||
List<AiVideoReportData> selectTeamDailyConsumeList(String statDate, Long deptId);
|
||||
|
||||
/**
|
||||
* 团队每日消耗(按部门 ID,团队后台)
|
||||
*/
|
||||
List<AiVideoReportData> selectTeamDailyConsumeByDeptId(String statDate, Long deptId);
|
||||
|
||||
/**
|
||||
* 按视频订单成功结果回写统计来源表(按小时、部门、账号聚合累加)。
|
||||
*
|
||||
* @param createTime 任务创建时间
|
||||
* @param deptId 部门ID
|
||||
* @param userId 账号ID
|
||||
* @param score 消耗积分增量
|
||||
* @param useTokens 三方tokens增量
|
||||
*/
|
||||
void syncVideoConsumeIncrement(Date createTime, Long deptId, Long userId, BigDecimal score, Long useTokens);
|
||||
|
||||
/**
|
||||
* 按充值/退款成功结果回写统计来源表(按小时、部门聚合累加)。
|
||||
*
|
||||
* @param createTime 订单创建时间
|
||||
* @param deptId 部门ID
|
||||
* @param rechargeScore 实际充值积分增量(充值为正,退款为负)
|
||||
*/
|
||||
void syncRechargeScoreIncrement(Date createTime, Long deptId, BigDecimal rechargeScore);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,30 @@
|
|||
package com.ruoyi.ai.service.impl;
|
||||
|
||||
import java.util.List;
|
||||
import java.math.BigDecimal;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.ruoyi.common.enums.ChargeRefundOrderStatusType;
|
||||
import com.ruoyi.common.enums.ChargeRefundOrderType;
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
import com.ruoyi.common.utils.DateUtils;
|
||||
import com.ruoyi.common.utils.SecurityUtils;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.common.utils.uuid.IdUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.ruoyi.ai.domain.AiChargeRefundOrder;
|
||||
import com.ruoyi.ai.mapper.AiChargeRefundOrderMapper;
|
||||
import com.ruoyi.ai.domain.AiChargeRefundOrder;
|
||||
import com.ruoyi.ai.service.IAiVideoReportDataService;
|
||||
import com.ruoyi.ai.service.IAiChargeRefundOrderService;
|
||||
|
||||
/**
|
||||
* 充值/退款订单 Service 实现
|
||||
* 团队(部门)充值退款订单Service业务层处理
|
||||
*
|
||||
* @author shi
|
||||
* @date 2026-04-17
|
||||
*/
|
||||
@Service
|
||||
public class AiChargeRefundOrderServiceImpl implements IAiChargeRefundOrderService {
|
||||
|
|
@ -16,23 +32,149 @@ public class AiChargeRefundOrderServiceImpl implements IAiChargeRefundOrderServi
|
|||
@Autowired
|
||||
private AiChargeRefundOrderMapper aiChargeRefundOrderMapper;
|
||||
|
||||
@Autowired
|
||||
private IAiVideoReportDataService aiVideoReportDataService;
|
||||
|
||||
/**
|
||||
* 查询团队(部门)充值退款订单
|
||||
*
|
||||
* @param id 团队(部门)充值退款订单主键
|
||||
* @return 团队(部门)充值退款订单
|
||||
*/
|
||||
@Override
|
||||
public AiChargeRefundOrder selectById(Long id) {
|
||||
return aiChargeRefundOrderMapper.selectById(id);
|
||||
public AiChargeRefundOrder selectAiChargeRefundOrderById(Long id) {
|
||||
return aiChargeRefundOrderMapper.selectAiChargeRefundOrderById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询团队(部门)充值退款订单列表
|
||||
*
|
||||
* @param aiChargeRefundOrder 团队(部门)充值退款订单
|
||||
* @return 团队(部门)充值退款订单
|
||||
*/
|
||||
@Override
|
||||
public int insert(AiChargeRefundOrder entity) {
|
||||
return aiChargeRefundOrderMapper.insert(entity);
|
||||
public List<AiChargeRefundOrder> selectAiChargeRefundOrderList(AiChargeRefundOrder aiChargeRefundOrder) {
|
||||
return aiChargeRefundOrderMapper.selectAiChargeRefundOrderList(aiChargeRefundOrder);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询团队(部门)充值退款订单列表
|
||||
*
|
||||
* @param aiChargeRefundOrder 团队(部门)充值退款订单
|
||||
* @return 团队(部门)充值退款订单
|
||||
*/
|
||||
@Override
|
||||
public int updateById(AiChargeRefundOrder entity) {
|
||||
return aiChargeRefundOrderMapper.updateById(entity);
|
||||
public IPage<AiChargeRefundOrder> selectAiChargeRefundOrderPage(Page page, AiChargeRefundOrder aiChargeRefundOrder) {
|
||||
if (aiChargeRefundOrder != null) {
|
||||
aiChargeRefundOrder.setDeptName(null);
|
||||
}
|
||||
LambdaQueryWrapper<AiChargeRefundOrder> query = Wrappers.lambdaQuery(aiChargeRefundOrder);
|
||||
query.eq(AiChargeRefundOrder::getDelFlag, "0");
|
||||
return aiChargeRefundOrderMapper.selectPage(page, query);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增团队(部门)充值退款订单
|
||||
*
|
||||
* @param aiChargeRefundOrder 团队(部门)充值退款订单
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public int deleteById(Long id) {
|
||||
public int insertAiChargeRefundOrder(AiChargeRefundOrder aiChargeRefundOrder) {
|
||||
validateChargeAmount(aiChargeRefundOrder);
|
||||
if (StringUtils.isEmpty(aiChargeRefundOrder.getOrderNum())) {
|
||||
aiChargeRefundOrder.setOrderNum("CR" + IdUtils.fastSimpleUUID());
|
||||
}
|
||||
if (aiChargeRefundOrder.getStatus() == null) {
|
||||
aiChargeRefundOrder.setStatus(ChargeRefundOrderStatusType.SUCCESS.getCode());
|
||||
}
|
||||
aiChargeRefundOrder.setDelFlag("0");
|
||||
aiChargeRefundOrder.setCreateBy(SecurityUtils.getUsername());
|
||||
aiChargeRefundOrder.setCreateTime(DateUtils.getNowDate());
|
||||
int rows = aiChargeRefundOrderMapper.insert(aiChargeRefundOrder);
|
||||
syncRechargeReportData(aiChargeRefundOrder);
|
||||
return rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改团队(部门)充值退款订单
|
||||
*
|
||||
* @param aiChargeRefundOrder 团队(部门)充值退款订单
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public int updateAiChargeRefundOrder(AiChargeRefundOrder aiChargeRefundOrder) {
|
||||
validateChargeAmount(aiChargeRefundOrder);
|
||||
aiChargeRefundOrder.setUpdateTime(DateUtils.getNowDate());
|
||||
int rows = aiChargeRefundOrderMapper.updateById(aiChargeRefundOrder);
|
||||
if (rows > 0) {
|
||||
AiChargeRefundOrder fresh = aiChargeRefundOrderMapper.selectById(aiChargeRefundOrder.getId());
|
||||
syncRechargeReportData(fresh);
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除团队(部门)充值退款订单
|
||||
*
|
||||
* @param ids 需要删除的团队(部门)充值退款订单主键
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public int deleteAiChargeRefundOrderByIds(Long[] ids)
|
||||
{
|
||||
return aiChargeRefundOrderMapper.deleteAiChargeRefundOrderByIds(ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除团队(部门)充值退款订单信息
|
||||
*
|
||||
* @param id 团队(部门)充值退款订单主键
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public int deleteAiChargeRefundOrderById(Long id)
|
||||
{
|
||||
return aiChargeRefundOrderMapper.deleteById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 充值/退款单完成后,按“订单创建时间”同步到团队统计来源表。
|
||||
*
|
||||
* @param order 充值退款订单
|
||||
*/
|
||||
private void syncRechargeReportData(AiChargeRefundOrder order) {
|
||||
if (order == null || order.getCreateTime() == null || order.getDeptId() == null) {
|
||||
return;
|
||||
}
|
||||
if (order.getStatus() == null || order.getStatus() != ChargeRefundOrderStatusType.SUCCESS.getCode()) {
|
||||
return;
|
||||
}
|
||||
if (order.getOrderType() == null || order.getAmount() == null) {
|
||||
return;
|
||||
}
|
||||
BigDecimal rechargeScore;
|
||||
int type = order.getOrderType().intValue();
|
||||
if (type == ChargeRefundOrderType.REFUND.getCode()) {
|
||||
rechargeScore = order.getAmount().negate();
|
||||
} else {
|
||||
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("充值、退款类型的积分须填写非负数");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,23 @@
|
|||
package com.ruoyi.ai.service.impl;
|
||||
|
||||
import java.util.List;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.ruoyi.common.utils.DateUtils;
|
||||
import com.ruoyi.common.utils.SecurityUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.ruoyi.ai.domain.AiDeptArkConfig;
|
||||
import com.ruoyi.ai.mapper.AiDeptArkConfigMapper;
|
||||
import com.ruoyi.ai.domain.AiDeptArkConfig;
|
||||
import com.ruoyi.ai.service.IAiDeptArkConfigService;
|
||||
|
||||
/**
|
||||
* 部门方舟配置 Service 实现
|
||||
* 团队(部门)对应火山引擎配置Service业务层处理
|
||||
*
|
||||
* @author shi
|
||||
* @date 2026-04-17
|
||||
*/
|
||||
@Service
|
||||
public class AiDeptArkConfigServiceImpl implements IAiDeptArkConfigService {
|
||||
|
|
@ -16,23 +25,89 @@ public class AiDeptArkConfigServiceImpl implements IAiDeptArkConfigService {
|
|||
@Autowired
|
||||
private AiDeptArkConfigMapper aiDeptArkConfigMapper;
|
||||
|
||||
/**
|
||||
* 查询团队(部门)对应火山引擎配置
|
||||
*
|
||||
* @param id 团队(部门)对应火山引擎配置主键
|
||||
* @return 团队(部门)对应火山引擎配置
|
||||
*/
|
||||
@Override
|
||||
public AiDeptArkConfig selectById(Long id) {
|
||||
public AiDeptArkConfig selectAiDeptArkConfigById(String id) {
|
||||
return aiDeptArkConfigMapper.selectById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询团队(部门)对应火山引擎配置列表
|
||||
*
|
||||
* @param aiDeptArkConfig 团队(部门)对应火山引擎配置
|
||||
* @return 团队(部门)对应火山引擎配置
|
||||
*/
|
||||
@Override
|
||||
public int insert(AiDeptArkConfig entity) {
|
||||
return aiDeptArkConfigMapper.insert(entity);
|
||||
public List<AiDeptArkConfig> selectAiDeptArkConfigList(AiDeptArkConfig aiDeptArkConfig) {
|
||||
LambdaQueryWrapper<AiDeptArkConfig> query = Wrappers.lambdaQuery(aiDeptArkConfig);
|
||||
query.orderByDesc(AiDeptArkConfig::getId);
|
||||
return aiDeptArkConfigMapper.selectList(query);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询团队(部门)对应火山引擎配置列表
|
||||
*
|
||||
* @param aiDeptArkConfig 团队(部门)对应火山引擎配置
|
||||
* @return 团队(部门)对应火山引擎配置
|
||||
*/
|
||||
@Override
|
||||
public int updateById(AiDeptArkConfig entity) {
|
||||
return aiDeptArkConfigMapper.updateById(entity);
|
||||
public IPage<AiDeptArkConfig> selectAiDeptArkConfigPage(Page page, AiDeptArkConfig aiDeptArkConfig) {
|
||||
LambdaQueryWrapper<AiDeptArkConfig> query = Wrappers.lambdaQuery(aiDeptArkConfig);
|
||||
return aiDeptArkConfigMapper.selectPage(page, query);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增团队(部门)对应火山引擎配置
|
||||
*
|
||||
* @param aiDeptArkConfig 团队(部门)对应火山引擎配置
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public int deleteById(Long id) {
|
||||
public int insertAiDeptArkConfig(AiDeptArkConfig aiDeptArkConfig) {
|
||||
aiDeptArkConfig.setCreateBy(SecurityUtils.getUsername());
|
||||
aiDeptArkConfig.setCreateTime(DateUtils.getNowDate());
|
||||
return aiDeptArkConfigMapper.insert(aiDeptArkConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改团队(部门)对应火山引擎配置
|
||||
*
|
||||
* @param aiDeptArkConfig 团队(部门)对应火山引擎配置
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public int updateAiDeptArkConfig(AiDeptArkConfig aiDeptArkConfig) {
|
||||
aiDeptArkConfig.setUpdateBy(SecurityUtils.getUsername());
|
||||
aiDeptArkConfig.setUpdateTime(DateUtils.getNowDate());
|
||||
return aiDeptArkConfigMapper.updateById(aiDeptArkConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除团队(部门)对应火山引擎配置
|
||||
*
|
||||
* @param ids 需要删除的团队(部门)对应火山引擎配置主键
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public int deleteAiDeptArkConfigByIds(String[] ids)
|
||||
{
|
||||
return aiDeptArkConfigMapper.deleteBatchIds(java.util.Arrays.asList(ids));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除团队(部门)对应火山引擎配置信息
|
||||
*
|
||||
* @param id 团队(部门)对应火山引擎配置主键
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public int deleteAiDeptArkConfigById(String id)
|
||||
{
|
||||
return aiDeptArkConfigMapper.deleteById(id);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,22 @@
|
|||
package com.ruoyi.ai.service.impl;
|
||||
|
||||
import java.util.List;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.ruoyi.common.utils.DateUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.ruoyi.ai.domain.AiGroupBalanceChangeRecord;
|
||||
import com.ruoyi.ai.mapper.AiGroupBalanceChangeRecordMapper;
|
||||
import com.ruoyi.ai.domain.AiGroupBalanceChangeRecord;
|
||||
import com.ruoyi.ai.service.IAiGroupBalanceChangeRecordService;
|
||||
|
||||
/**
|
||||
* 集团余额变动记录 Service 实现
|
||||
* 团队(部门)余额变动Service业务层处理
|
||||
*
|
||||
* @author shi
|
||||
* @date 2026-04-17
|
||||
*/
|
||||
@Service
|
||||
public class AiGroupBalanceChangeRecordServiceImpl implements IAiGroupBalanceChangeRecordService {
|
||||
|
|
@ -16,23 +24,87 @@ public class AiGroupBalanceChangeRecordServiceImpl implements IAiGroupBalanceCha
|
|||
@Autowired
|
||||
private AiGroupBalanceChangeRecordMapper aiGroupBalanceChangeRecordMapper;
|
||||
|
||||
/**
|
||||
* 查询团队(部门)余额变动
|
||||
*
|
||||
* @param id 团队(部门)余额变动主键
|
||||
* @return 团队(部门)余额变动
|
||||
*/
|
||||
@Override
|
||||
public AiGroupBalanceChangeRecord selectById(Long id) {
|
||||
public AiGroupBalanceChangeRecord selectAiGroupBalanceChangeRecordById(String id) {
|
||||
return aiGroupBalanceChangeRecordMapper.selectById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询团队(部门)余额变动列表
|
||||
*
|
||||
* @param aiGroupBalanceChangeRecord 团队(部门)余额变动
|
||||
* @return 团队(部门)余额变动
|
||||
*/
|
||||
@Override
|
||||
public int insert(AiGroupBalanceChangeRecord entity) {
|
||||
return aiGroupBalanceChangeRecordMapper.insert(entity);
|
||||
public List<AiGroupBalanceChangeRecord> selectAiGroupBalanceChangeRecordList(AiGroupBalanceChangeRecord aiGroupBalanceChangeRecord) {
|
||||
LambdaQueryWrapper<AiGroupBalanceChangeRecord> query = Wrappers.lambdaQuery(aiGroupBalanceChangeRecord);
|
||||
query.orderByDesc(AiGroupBalanceChangeRecord::getId);
|
||||
return aiGroupBalanceChangeRecordMapper.selectList(query);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询团队(部门)余额变动列表
|
||||
*
|
||||
* @param aiGroupBalanceChangeRecord 团队(部门)余额变动
|
||||
* @return 团队(部门)余额变动
|
||||
*/
|
||||
@Override
|
||||
public int updateById(AiGroupBalanceChangeRecord entity) {
|
||||
return aiGroupBalanceChangeRecordMapper.updateById(entity);
|
||||
public IPage<AiGroupBalanceChangeRecord> selectAiGroupBalanceChangeRecordPage(Page page, AiGroupBalanceChangeRecord aiGroupBalanceChangeRecord) {
|
||||
LambdaQueryWrapper<AiGroupBalanceChangeRecord> query = Wrappers.lambdaQuery(aiGroupBalanceChangeRecord);
|
||||
return aiGroupBalanceChangeRecordMapper.selectPage(page, query);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增团队(部门)余额变动
|
||||
*
|
||||
* @param aiGroupBalanceChangeRecord 团队(部门)余额变动
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public int deleteById(Long id) {
|
||||
public int insertAiGroupBalanceChangeRecord(AiGroupBalanceChangeRecord aiGroupBalanceChangeRecord) {
|
||||
aiGroupBalanceChangeRecord.setCreateTime(DateUtils.getNowDate());
|
||||
return aiGroupBalanceChangeRecordMapper.insert(aiGroupBalanceChangeRecord);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改团队(部门)余额变动
|
||||
*
|
||||
* @param aiGroupBalanceChangeRecord 团队(部门)余额变动
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public int updateAiGroupBalanceChangeRecord(AiGroupBalanceChangeRecord aiGroupBalanceChangeRecord) {
|
||||
aiGroupBalanceChangeRecord.setUpdateTime(DateUtils.getNowDate());
|
||||
return aiGroupBalanceChangeRecordMapper.updateById(aiGroupBalanceChangeRecord);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除团队(部门)余额变动
|
||||
*
|
||||
* @param ids 需要删除的团队(部门)余额变动主键
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public int deleteAiGroupBalanceChangeRecordByIds(String[] ids)
|
||||
{
|
||||
return aiGroupBalanceChangeRecordMapper.deleteBatchIds(java.util.Arrays.asList(ids));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除团队(部门)余额变动信息
|
||||
*
|
||||
* @param id 团队(部门)余额变动主键
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public int deleteAiGroupBalanceChangeRecordById(String id)
|
||||
{
|
||||
return aiGroupBalanceChangeRecordMapper.deleteById(id);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,6 +63,9 @@ public class AiOrderServiceImpl implements IAiOrderService {
|
|||
@Autowired
|
||||
private IByteDeptApiKeyService byteDeptApiKeyService;
|
||||
|
||||
@Autowired
|
||||
private IAiVideoReportDataService aiVideoReportDataService;
|
||||
|
||||
// 流水表:任务成功时回补
|
||||
private static final String TASK_SUCCESS_BACK_FILL_REMARK = "order.number.generation.successbackfill";
|
||||
|
||||
|
|
@ -248,6 +251,7 @@ public class AiOrderServiceImpl implements IAiOrderService {
|
|||
public void orderSuccess(AiOrder aiOrder) {
|
||||
aiOrder.setStatus(1);
|
||||
aiOrderMapper.updateById(aiOrder);
|
||||
syncVideoReportData(aiOrder);
|
||||
AiStatistics aiStatistics = new AiStatistics();
|
||||
aiStatistics.setSource(aiOrder.getSource());
|
||||
aiStatistics.setGenerateCount(1L);
|
||||
|
|
@ -356,4 +360,18 @@ public class AiOrderServiceImpl implements IAiOrderService {
|
|||
// BalanceChangerConstants.QUICK_VIDEO_GENERATION, TASK_SUCCESS_BALANCE_REMARK);
|
||||
return AjaxResult.success("callback success");
|
||||
}
|
||||
|
||||
/**
|
||||
* 任务成功后按“提交时间”写入团队消耗统计来源表。
|
||||
*
|
||||
* @param aiOrder 已成功订单
|
||||
*/
|
||||
private void syncVideoReportData(AiOrder aiOrder) {
|
||||
if (aiOrder == null || aiOrder.getCreateTime() == null || aiOrder.getDeptId() == null || aiOrder.getUserId() == null) {
|
||||
return;
|
||||
}
|
||||
BigDecimal score = aiOrder.getAmount() != null ? aiOrder.getAmount() : BigDecimal.ZERO;
|
||||
Long useTokens = aiOrder.getTotalUsage() != null ? aiOrder.getTotalUsage().longValue() : 0L;
|
||||
aiVideoReportDataService.syncVideoConsumeIncrement(aiOrder.getCreateTime(), aiOrder.getDeptId(), aiOrder.getUserId(), score, useTokens);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -303,7 +303,7 @@ public class AiUserServiceImpl implements IAiUserService {
|
|||
private AiUser getUserByInvitationCode(String invitationCode) {
|
||||
LambdaQueryWrapper<AiUser> query = Wrappers.lambdaQuery();
|
||||
query.eq(AiUser::getInvitationCode, invitationCode);
|
||||
query.eq(AiUser::getDelFlag, 0);
|
||||
query.eq(AiUser::getDelFlag, "0");
|
||||
return aiUserMapper.selectOne(query);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,61 +1,141 @@
|
|||
package com.ruoyi.ai.service.impl;
|
||||
|
||||
import com.ruoyi.ai.domain.AiVideoReportData;
|
||||
import com.ruoyi.ai.mapper.AiVideoReportDataMapper;
|
||||
import com.ruoyi.ai.service.IAiVideoReportDataService;
|
||||
import com.ruoyi.common.constant.RedisKey;
|
||||
import com.ruoyi.common.core.dto.DeptSummaryDTO;
|
||||
import 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.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 com.ruoyi.ai.mapper.AiVideoReportDataMapper;
|
||||
import com.ruoyi.ai.domain.AiVideoReportData;
|
||||
import com.ruoyi.ai.service.IAiVideoReportDataService;
|
||||
|
||||
/**
|
||||
* 视频报表数据 Service 实现
|
||||
* AI视频生成统计数据,作为其他统计报的数据源Service业务层处理
|
||||
*
|
||||
* @author shi
|
||||
* @date 2026-04-17
|
||||
*/
|
||||
@Service
|
||||
public class AiVideoReportDataServiceImpl implements IAiVideoReportDataService {
|
||||
|
||||
/** 与表字段 date_key 一致:yyyy-MM-dd HH(线程安全) */
|
||||
private static final DateTimeFormatter DATE_KEY_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH");
|
||||
|
||||
@Autowired
|
||||
private AiVideoReportDataMapper videoReportDataMapper;
|
||||
private AiVideoReportDataMapper aiVideoReportDataMapper;
|
||||
|
||||
/**
|
||||
* 查询AI视频生成统计数据,作为其他统计报的数据源
|
||||
*
|
||||
* @param id AI视频生成统计数据,作为其他统计报的数据源主键
|
||||
* @return AI视频生成统计数据,作为其他统计报的数据源
|
||||
*/
|
||||
@Override
|
||||
public AiVideoReportData selectById(Long id) {
|
||||
return videoReportDataMapper.selectById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int insert(AiVideoReportData entity) {
|
||||
return videoReportDataMapper.insert(entity);
|
||||
public AiVideoReportData selectAiVideoReportDataById(String id) {
|
||||
return aiVideoReportDataMapper.selectById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 部门近七日汇总数据
|
||||
* 查询AI视频生成统计数据,作为其他统计报的数据源列表
|
||||
*
|
||||
* @param aiVideoReportData AI视频生成统计数据,作为其他统计报的数据源
|
||||
* @return AI视频生成统计数据,作为其他统计报的数据源
|
||||
*/
|
||||
@Override
|
||||
@Cacheable(cacheNames = RedisKey.CACHE_DEPT_SUMMARY, key = "#deptId")
|
||||
public DeptSummaryDTO getSevenDayDeptSummaryData(Long deptId) {
|
||||
Date endTime = new Date();
|
||||
// 获取今天的0点,再减去7天
|
||||
Date todayZero = DateUtils.truncate(endTime, Calendar.DAY_OF_MONTH);
|
||||
Date startTime = DateUtils.addDays(todayZero, -7);
|
||||
|
||||
String startHour = formatDateKey(startTime);
|
||||
String endHour = formatDateKey(endTime);
|
||||
return videoReportDataMapper.selectOneDeptSummaryData(deptId, startHour, endHour);
|
||||
public List<AiVideoReportData> selectAiVideoReportDataList(AiVideoReportData aiVideoReportData) {
|
||||
LambdaQueryWrapper<AiVideoReportData> query = Wrappers.lambdaQuery(aiVideoReportData);
|
||||
query.orderByDesc(AiVideoReportData::getId);
|
||||
return aiVideoReportDataMapper.selectList(query);
|
||||
}
|
||||
|
||||
private static String formatDateKey(Date date) {
|
||||
LocalDateTime ldt = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
|
||||
return DATE_KEY_FORMAT.format(ldt);
|
||||
/**
|
||||
* 分页查询AI视频生成统计数据,作为其他统计报的数据源列表
|
||||
*
|
||||
* @param aiVideoReportData AI视频生成统计数据,作为其他统计报的数据源
|
||||
* @return AI视频生成统计数据,作为其他统计报的数据源
|
||||
*/
|
||||
@Override
|
||||
public IPage<AiVideoReportData> selectAiVideoReportDataPage(Page page, AiVideoReportData aiVideoReportData) {
|
||||
LambdaQueryWrapper<AiVideoReportData> query = Wrappers.lambdaQuery(aiVideoReportData);
|
||||
return aiVideoReportDataMapper.selectPage(page, query);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增AI视频生成统计数据,作为其他统计报的数据源
|
||||
*
|
||||
* @param aiVideoReportData AI视频生成统计数据,作为其他统计报的数据源
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public int insertAiVideoReportData(AiVideoReportData aiVideoReportData) {
|
||||
aiVideoReportData.setCreateTime(DateUtils.getNowDate());
|
||||
return aiVideoReportDataMapper.insert(aiVideoReportData);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改AI视频生成统计数据,作为其他统计报的数据源
|
||||
*
|
||||
* @param aiVideoReportData AI视频生成统计数据,作为其他统计报的数据源
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public int updateAiVideoReportData(AiVideoReportData aiVideoReportData) {
|
||||
aiVideoReportData.setUpdateTime(DateUtils.getNowDate());
|
||||
return aiVideoReportDataMapper.updateById(aiVideoReportData);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除AI视频生成统计数据,作为其他统计报的数据源
|
||||
*
|
||||
* @param ids 需要删除的AI视频生成统计数据,作为其他统计报的数据源主键
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public int deleteAiVideoReportDataByIds(String[] ids)
|
||||
{
|
||||
return aiVideoReportDataMapper.deleteBatchIds(java.util.Arrays.asList(ids));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除AI视频生成统计数据,作为其他统计报的数据源信息
|
||||
*
|
||||
* @param id AI视频生成统计数据,作为其他统计报的数据源主键
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public int deleteAiVideoReportDataById(String id)
|
||||
{
|
||||
return aiVideoReportDataMapper.deleteById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AiVideoReportData> selectTeamDailyConsumeList(String statDate, Long deptId) {
|
||||
return aiVideoReportDataMapper.selectTeamDailyConsumeList(statDate, deptId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AiVideoReportData> selectTeamDailyConsumeByDeptId(String statDate, Long deptId) {
|
||||
return aiVideoReportDataMapper.selectTeamDailyConsumeByDeptId(statDate, deptId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void syncVideoConsumeIncrement(Date createTime, Long deptId, Long userId, BigDecimal score, Long useTokens) {
|
||||
if (createTime == null || deptId == null || userId == null || score == null || useTokens == null) {
|
||||
return;
|
||||
}
|
||||
String dateKey = new SimpleDateFormat("yyyyMMddHH").format(createTime);
|
||||
aiVideoReportDataMapper.upsertVideoConsumeIncrement(dateKey, deptId, userId, score, 1L, useTokens);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void syncRechargeScoreIncrement(Date createTime, Long deptId, BigDecimal rechargeScore) {
|
||||
if (createTime == null || deptId == null || rechargeScore == null) {
|
||||
return;
|
||||
}
|
||||
String dateKey = new SimpleDateFormat("yyyyMMddHH").format(createTime);
|
||||
aiVideoReportDataMapper.upsertRechargeScoreIncrement(dateKey, deptId, rechargeScore);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import java.text.SimpleDateFormat;
|
|||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.ruoyi.common.constant.BalanceChangerConstants;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
|
@ -60,19 +59,19 @@ public class DeptChargeRefundServiceImpl implements IDeptChargeRefundService {
|
|||
// 1) 手工入账订单,状态直接为已完成
|
||||
AiChargeRefundOrder order = new AiChargeRefundOrder();
|
||||
order.setDelFlag("0");
|
||||
order.setCreateBy(SecurityUtils.getUserId());
|
||||
order.setCreateBy(SecurityUtils.getUsername());
|
||||
order.setCreateTime(now);
|
||||
order.setUpdateTime(now);
|
||||
order.setOrderNum(orderNum);
|
||||
order.setDeptId(request.getDeptId());
|
||||
order.setOrderType(request.getOrderType());
|
||||
order.setOrderType(Long.valueOf(request.getOrderType()));
|
||||
// 金额两位小数:向零截断(非四舍五入),避免入账金额被抬高
|
||||
order.setMoney(request.getMoney().setScale(2, RoundingMode.DOWN));
|
||||
order.setAmount(amountBd);
|
||||
order.setRemark(request.getRemark());
|
||||
order.setStatus(ChargeRefundOrderStatusType.SUCCESS.getCode());
|
||||
|
||||
aiChargeRefundOrderService.insert(order);
|
||||
aiChargeRefundOrderService.insertAiChargeRefundOrder(order);
|
||||
|
||||
// 2) 原子更新部门积分;退款时 rows==0 表示余额不足或部门无效,依赖事务回滚撤销上一 INSERT
|
||||
int rows;
|
||||
|
|
@ -102,22 +101,22 @@ public class DeptChargeRefundServiceImpl implements IDeptChargeRefundService {
|
|||
record.setRelationOrderNo(orderNum);
|
||||
record.setDeptId(request.getDeptId());
|
||||
record.setType(orderType == ChargeRefundOrderType.CHARGE
|
||||
? GroupBalanceChangeType.RECHARGE.getCode()
|
||||
: GroupBalanceChangeType.REFUND.getCode());
|
||||
? Long.valueOf(GroupBalanceChangeType.RECHARGE.getCode())
|
||||
: Long.valueOf(GroupBalanceChangeType.REFUND.getCode()));
|
||||
record.setChangeAmount(signedChange);
|
||||
record.setResultAmount(dept.getBalance());
|
||||
record.setRemark(request.getRemark());
|
||||
record.setCreateBy(SecurityUtils.getUserId());
|
||||
record.setCreateBy(SecurityUtils.getUsername());
|
||||
record.setCreateTime(now);
|
||||
record.setUpdateTime(now);
|
||||
|
||||
aiGroupBalanceChangeRecordService.insert(record);
|
||||
aiGroupBalanceChangeRecordService.insertAiGroupBalanceChangeRecord(record);
|
||||
}
|
||||
|
||||
/** 业务单号前缀 + 日序 + 随机后缀,保证与流水 relation_order_no 一致。 */
|
||||
private static String buildOrderNum() {
|
||||
String uuid = UUID.randomUUID().toString().replace("-", "").substring(0, 8);
|
||||
String dateTime = new SimpleDateFormat("yyyyMMdd").format(new Date());
|
||||
return BalanceChangerConstants.OrderNoPrefix.RECHARGE_REFUND_PREFIX + dateTime + uuid;
|
||||
return "CG" + dateTime + uuid;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ import com.ruoyi.common.core.domain.entity.SysDept;
|
|||
import com.ruoyi.common.core.request.ai.AiUserDeptScoreRequest;
|
||||
import com.ruoyi.common.enums.GroupBalanceChangeType;
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
import com.ruoyi.common.utils.DateUtils;
|
||||
import com.ruoyi.common.utils.SecurityUtils;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.system.service.ISysDeptService;
|
||||
|
|
@ -78,7 +77,9 @@ public class DeptUserScoreTransferTxService {
|
|||
}
|
||||
|
||||
String orderNum = buildOrderNum();
|
||||
aiUserService.addUserBalance(orderNum, user.getId(), amount.negate(), BalanceChangerConstants.DEPT_SCORE_RECLAIM, request.getRemark());
|
||||
String remark = buildRemark(request.getRemark(), "用户积分回收至部门");
|
||||
|
||||
aiUserService.addUserBalance(orderNum, user.getId(), amount.negate(), BalanceChangerConstants.DEPT_SCORE_RECLAIM, remark);
|
||||
|
||||
int rows = deptService.addDeptBalance(deptId, amount);
|
||||
if (rows == 0) {
|
||||
|
|
@ -86,7 +87,7 @@ public class DeptUserScoreTransferTxService {
|
|||
}
|
||||
|
||||
BigDecimal deptBalAfter = getDeptBalance(deptId);
|
||||
insertGroupRecord(orderNum, deptId, GroupBalanceChangeType.RECLAIM.getCode(), amount, deptBalAfter, request.getRemark());
|
||||
insertGroupRecord(orderNum, deptId, GroupBalanceChangeType.RECLAIM.getCode(), amount, deptBalAfter, remark);
|
||||
}
|
||||
|
||||
private AiUser requireUserWithDept(Long id) {
|
||||
|
|
@ -131,17 +132,17 @@ public class DeptUserScoreTransferTxService {
|
|||
AiGroupBalanceChangeRecord record = new AiGroupBalanceChangeRecord();
|
||||
record.setRelationOrderNo(orderNum);
|
||||
record.setDeptId(deptId);
|
||||
record.setType(type);
|
||||
record.setType(Long.valueOf(type));
|
||||
record.setChangeAmount(signedChange);
|
||||
record.setResultAmount(resultBalance);
|
||||
record.setRemark(remark);
|
||||
record.setCreateBy(SecurityUtils.getUserId());
|
||||
aiGroupBalanceChangeRecordService.insert(record);
|
||||
record.setCreateBy(SecurityUtils.getUsername());
|
||||
aiGroupBalanceChangeRecordService.insertAiGroupBalanceChangeRecord(record);
|
||||
}
|
||||
|
||||
private static String buildOrderNum() {
|
||||
String uuid = UUID.randomUUID().toString().replace("-", "").substring(0, 8);
|
||||
String dateTime = new SimpleDateFormat("yyyyMMdd").format(new Date());
|
||||
return BalanceChangerConstants.OrderNoPrefix.ISSUE_RECLAIM_PREFIX + dateTime + uuid;
|
||||
return "DU" + dateTime + uuid;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
package com.ruoyi.system.domain.subteam;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 团队后台首页概览
|
||||
*/
|
||||
@Data
|
||||
public class SubteamOverviewVO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Long deptId;
|
||||
|
||||
private String deptName;
|
||||
|
||||
/** 团队积分余额(sys_dept.balance) */
|
||||
private BigDecimal balance;
|
||||
|
||||
/** AI 用户数量(ai_user,实时) */
|
||||
private Integer aiUserCount;
|
||||
|
||||
/** 近七日消耗积分(ai_video_report_data,可能来自缓存) */
|
||||
private BigDecimal last7DaysConsumeScore;
|
||||
|
||||
/** 近七日成功订单数(ai_video_report_data,可能来自缓存) */
|
||||
private Long last7DaysOrderCount;
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package com.ruoyi.system.domain.subteam;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 团队视频统计汇总(近七日消耗/订单数)
|
||||
*/
|
||||
@Data
|
||||
public class SubteamVideoMetrics implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private BigDecimal consumeScore;
|
||||
|
||||
private Long orderCount;
|
||||
}
|
||||
|
|
@ -421,13 +421,13 @@ public class SysDeptServiceImpl implements ISysDeptService
|
|||
AiGroupBalanceChangeRecord record = new AiGroupBalanceChangeRecord();
|
||||
record.setRelationOrderNo(null);
|
||||
record.setDeptId(request.getDeptId());
|
||||
record.setType(GroupBalanceChangeType.MANUAL_ADJUST.getCode());
|
||||
record.setType(Long.valueOf(GroupBalanceChangeType.MANUAL_ADJUST.getCode()));
|
||||
record.setChangeAmount(delta);
|
||||
record.setResultAmount(dept.getBalance());
|
||||
record.setRemark(request.getRemark());
|
||||
record.setCreateBy(SecurityUtils.getUserId());
|
||||
record.setCreateBy(SecurityUtils.getUsername());
|
||||
|
||||
aiGroupBalanceChangeRecordService.insert(record);
|
||||
aiGroupBalanceChangeRecordService.insertAiGroupBalanceChangeRecord(record);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
package com.ruoyi.system.service.subteam;
|
||||
|
||||
import java.util.List;
|
||||
import com.ruoyi.ai.domain.AiBalanceChangeRecord;
|
||||
import com.ruoyi.ai.domain.AiChargeRefundOrder;
|
||||
import com.ruoyi.ai.domain.AiGroupBalanceChangeRecord;
|
||||
import com.ruoyi.ai.domain.AiOrder;
|
||||
import com.ruoyi.ai.domain.AiVideoReportData;
|
||||
|
||||
public interface ISubteamDataQueryService {
|
||||
|
||||
List<AiOrder> selectVideoOrders(AiOrder query);
|
||||
|
||||
List<AiChargeRefundOrder> selectChargeRefundOrders(AiChargeRefundOrder query);
|
||||
|
||||
List<AiBalanceChangeRecord> selectUserBalanceRecords(AiBalanceChangeRecord query);
|
||||
|
||||
List<AiGroupBalanceChangeRecord> selectGroupBalanceRecords(AiGroupBalanceChangeRecord query);
|
||||
|
||||
List<AiVideoReportData> selectTeamDailyConsume(String statDate);
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
package com.ruoyi.system.service.subteam;
|
||||
|
||||
import com.ruoyi.system.domain.subteam.SubteamOverviewVO;
|
||||
|
||||
public interface ISubteamOverviewService {
|
||||
|
||||
SubteamOverviewVO loadOverview();
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package com.ruoyi.system.service.subteam;
|
||||
|
||||
/**
|
||||
* 团队后台数据范围:当前登录人所属部门(团队)
|
||||
*/
|
||||
public interface ISubteamScopeService {
|
||||
|
||||
/**
|
||||
* 当前账号所属团队部门 ID(sys_user.dept_id)
|
||||
*/
|
||||
Long currentTeamDeptId();
|
||||
|
||||
void assertSysUserInTeam(Long sysUserId);
|
||||
|
||||
void assertAiUserInTeam(Long aiUserId);
|
||||
|
||||
void assertAiOrderBelongsToTeam(Long orderId);
|
||||
|
||||
void assertChargeRefundBelongsToTeam(Long orderPkId);
|
||||
|
||||
void assertGroupBalanceRecordBelongsToTeam(String recordId);
|
||||
|
||||
void assertAiBalanceRecordVisible(Long recordId, Long teamDeptId);
|
||||
}
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
package com.ruoyi.system.service.subteam.impl;
|
||||
|
||||
import java.util.List;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.ruoyi.ai.domain.AiBalanceChangeRecord;
|
||||
import com.ruoyi.ai.domain.AiChargeRefundOrder;
|
||||
import com.ruoyi.ai.domain.AiGroupBalanceChangeRecord;
|
||||
import com.ruoyi.ai.domain.AiOrder;
|
||||
import com.ruoyi.ai.domain.AiVideoReportData;
|
||||
import com.ruoyi.ai.mapper.AiBalanceChangeRecordMapper;
|
||||
import com.ruoyi.ai.mapper.AiChargeRefundOrderMapper;
|
||||
import com.ruoyi.ai.mapper.AiGroupBalanceChangeRecordMapper;
|
||||
import com.ruoyi.ai.mapper.AiOrderMapper;
|
||||
import com.ruoyi.ai.service.IAiVideoReportDataService;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.system.service.subteam.ISubteamDataQueryService;
|
||||
import com.ruoyi.system.service.subteam.ISubteamScopeService;
|
||||
|
||||
@Service
|
||||
public class SubteamDataQueryServiceImpl implements ISubteamDataQueryService {
|
||||
|
||||
@Autowired
|
||||
private ISubteamScopeService subteamScopeService;
|
||||
|
||||
@Autowired
|
||||
private AiOrderMapper aiOrderMapper;
|
||||
|
||||
@Autowired
|
||||
private AiChargeRefundOrderMapper aiChargeRefundOrderMapper;
|
||||
|
||||
@Autowired
|
||||
private AiBalanceChangeRecordMapper aiBalanceChangeRecordMapper;
|
||||
|
||||
@Autowired
|
||||
private AiGroupBalanceChangeRecordMapper aiGroupBalanceChangeRecordMapper;
|
||||
|
||||
@Autowired
|
||||
private IAiVideoReportDataService aiVideoReportDataService;
|
||||
|
||||
@Override
|
||||
public List<AiOrder> selectVideoOrders(AiOrder query) {
|
||||
Long deptId = subteamScopeService.currentTeamDeptId();
|
||||
query.setDeptId(deptId);
|
||||
return aiOrderMapper.selectAiOrderList(query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AiChargeRefundOrder> selectChargeRefundOrders(AiChargeRefundOrder query) {
|
||||
Long deptId = subteamScopeService.currentTeamDeptId();
|
||||
query.setDeptId(deptId);
|
||||
return aiChargeRefundOrderMapper.selectAiChargeRefundOrderList(query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AiBalanceChangeRecord> selectUserBalanceRecords(AiBalanceChangeRecord query) {
|
||||
Long deptId = subteamScopeService.currentTeamDeptId();
|
||||
return aiBalanceChangeRecordMapper.selectAiBalanceChangeRecordListByAiUserDept(query, deptId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AiGroupBalanceChangeRecord> selectGroupBalanceRecords(AiGroupBalanceChangeRecord query) {
|
||||
Long deptId = subteamScopeService.currentTeamDeptId();
|
||||
query.setDeptId(deptId);
|
||||
return aiGroupBalanceChangeRecordMapper.selectList(
|
||||
Wrappers.lambdaQuery(query).orderByDesc(AiGroupBalanceChangeRecord::getId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AiVideoReportData> selectTeamDailyConsume(String statDate) {
|
||||
if (StringUtils.isEmpty(statDate)) {
|
||||
return java.util.Collections.emptyList();
|
||||
}
|
||||
Long deptId = subteamScopeService.currentTeamDeptId();
|
||||
return aiVideoReportDataService.selectTeamDailyConsumeByDeptId(statDate, deptId);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
package com.ruoyi.system.service.subteam.impl;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.ruoyi.ai.mapper.AiVideoReportDataMapper;
|
||||
import com.ruoyi.ai.service.IAiUserService;
|
||||
import com.ruoyi.common.core.domain.entity.SysDept;
|
||||
import com.ruoyi.system.domain.subteam.SubteamOverviewVO;
|
||||
import com.ruoyi.system.domain.subteam.SubteamVideoMetrics;
|
||||
import com.ruoyi.system.mapper.SysDeptMapper;
|
||||
import com.ruoyi.system.service.subteam.ISubteamOverviewService;
|
||||
import com.ruoyi.system.service.subteam.ISubteamScopeService;
|
||||
import com.ruoyi.common.core.redis.RedisCache;
|
||||
|
||||
@Service
|
||||
public class SubteamOverviewServiceImpl implements ISubteamOverviewService {
|
||||
|
||||
private static final int METRICS_CACHE_MINUTES = 5;
|
||||
|
||||
@Autowired
|
||||
private ISubteamScopeService subteamScopeService;
|
||||
|
||||
@Autowired
|
||||
private SysDeptMapper sysDeptMapper;
|
||||
|
||||
@Autowired
|
||||
private IAiUserService aiUserService;
|
||||
|
||||
@Autowired
|
||||
private AiVideoReportDataMapper aiVideoReportDataMapper;
|
||||
|
||||
@Autowired
|
||||
private RedisCache redisCache;
|
||||
|
||||
@Override
|
||||
public SubteamOverviewVO loadOverview() {
|
||||
Long deptId = subteamScopeService.currentTeamDeptId();
|
||||
SysDept dept = sysDeptMapper.selectDeptById(deptId);
|
||||
SubteamOverviewVO vo = new SubteamOverviewVO();
|
||||
vo.setDeptId(deptId);
|
||||
vo.setDeptName(dept != null ? dept.getDeptName() : "");
|
||||
vo.setBalance(dept != null && dept.getBalance() != null ? dept.getBalance() : BigDecimal.ZERO);
|
||||
vo.setAiUserCount(aiUserService.countAiUserByDeptId(deptId));
|
||||
|
||||
LocalDate end = LocalDate.now();
|
||||
LocalDate start = end.minusDays(6);
|
||||
String startDay = start.format(DateTimeFormatter.BASIC_ISO_DATE);
|
||||
String endDay = end.format(DateTimeFormatter.BASIC_ISO_DATE);
|
||||
String cacheKey = "subteam:videoMetrics:" + deptId + ":" + startDay + ":" + endDay;
|
||||
SubteamVideoMetrics metrics = redisCache.getCacheObject(cacheKey);
|
||||
if (metrics == null) {
|
||||
metrics = aiVideoReportDataMapper.selectDeptVideoMetricsBetween(deptId, startDay, endDay);
|
||||
if (metrics == null) {
|
||||
metrics = new SubteamVideoMetrics();
|
||||
}
|
||||
if (metrics.getConsumeScore() == null) {
|
||||
metrics.setConsumeScore(BigDecimal.ZERO);
|
||||
}
|
||||
if (metrics.getOrderCount() == null) {
|
||||
metrics.setOrderCount(0L);
|
||||
}
|
||||
redisCache.setCacheObject(cacheKey, metrics, METRICS_CACHE_MINUTES, TimeUnit.MINUTES);
|
||||
}
|
||||
vo.setLast7DaysConsumeScore(metrics.getConsumeScore());
|
||||
vo.setLast7DaysOrderCount(metrics.getOrderCount());
|
||||
return vo;
|
||||
}
|
||||
}
|
||||
|
|
@ -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("无权查看该余额变动");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,113 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.ruoyi.ai.mapper.AiChargeRefundOrderMapper">
|
||||
|
||||
<resultMap type="AiChargeRefundOrder" id="AiChargeRefundOrderResult">
|
||||
<result property="id" column="id" />
|
||||
<result property="delFlag" column="del_flag" />
|
||||
<result property="createBy" column="create_by" />
|
||||
<result property="createTime" column="create_time" />
|
||||
<result property="updateTime" column="update_time" />
|
||||
<result property="orderNum" column="order_num" />
|
||||
<result property="thirdPartyOrderNum" column="third_party_order_num" />
|
||||
<result property="deptId" column="dept_id" />
|
||||
<result property="deptName" column="dept_name" />
|
||||
<result property="orderType" column="order_type" />
|
||||
<result property="money" column="money" />
|
||||
<result property="amount" column="amount" />
|
||||
<result property="remark" column="remark" />
|
||||
<result property="status" column="status" />
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectAiChargeRefundOrderVo">
|
||||
select o.id, o.del_flag, o.create_by, o.create_time, o.update_time, o.order_num, o.third_party_order_num, o.dept_id,
|
||||
d.dept_name as dept_name, o.order_type, o.money, o.amount, o.remark, o.status
|
||||
from ai_charge_refund_order o
|
||||
left join sys_dept d on d.dept_id = o.dept_id and d.del_flag = '0'
|
||||
</sql>
|
||||
|
||||
<select id="selectAiChargeRefundOrderList" parameterType="AiChargeRefundOrder" resultMap="AiChargeRefundOrderResult">
|
||||
<include refid="selectAiChargeRefundOrderVo"/>
|
||||
<where>
|
||||
and o.del_flag = '0'
|
||||
<if test="orderNum != null and orderNum != ''"> and o.order_num = #{orderNum}</if>
|
||||
<if test="thirdPartyOrderNum != null and thirdPartyOrderNum != ''"> and o.third_party_order_num = #{thirdPartyOrderNum}</if>
|
||||
<if test="deptId != null "> and o.dept_id = #{deptId}</if>
|
||||
<if test="deptName != null and deptName != ''"> and d.dept_name like concat('%', #{deptName}, '%')</if>
|
||||
<if test="orderType != null "> and o.order_type = #{orderType}</if>
|
||||
<if test="money != null "> and o.money = #{money}</if>
|
||||
<if test="amount != null "> and o.amount = #{amount}</if>
|
||||
<if test="status != null "> and o.status = #{status}</if>
|
||||
</where>
|
||||
order by o.id desc
|
||||
</select>
|
||||
|
||||
<select id="selectAiChargeRefundOrderById" parameterType="Long" resultMap="AiChargeRefundOrderResult">
|
||||
<include refid="selectAiChargeRefundOrderVo"/>
|
||||
where o.id = #{id}
|
||||
</select>
|
||||
|
||||
<insert id="insertAiChargeRefundOrder" parameterType="AiChargeRefundOrder" useGeneratedKeys="true" keyProperty="id">
|
||||
insert into ai_charge_refund_order
|
||||
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||
<if test="delFlag != null and delFlag != ''">del_flag,</if>
|
||||
<if test="createBy != null">create_by,</if>
|
||||
<if test="createTime != null">create_time,</if>
|
||||
<if test="updateTime != null">update_time,</if>
|
||||
<if test="orderNum != null and orderNum != ''">order_num,</if>
|
||||
<if test="thirdPartyOrderNum != null">third_party_order_num,</if>
|
||||
<if test="deptId != null">dept_id,</if>
|
||||
<if test="orderType != null">order_type,</if>
|
||||
<if test="money != null">money,</if>
|
||||
<if test="amount != null">amount,</if>
|
||||
<if test="remark != null">remark,</if>
|
||||
<if test="status != null">status,</if>
|
||||
</trim>
|
||||
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
||||
<if test="delFlag != null and delFlag != ''">#{delFlag},</if>
|
||||
<if test="createBy != null">#{createBy},</if>
|
||||
<if test="createTime != null">#{createTime},</if>
|
||||
<if test="updateTime != null">#{updateTime},</if>
|
||||
<if test="orderNum != null and orderNum != ''">#{orderNum},</if>
|
||||
<if test="thirdPartyOrderNum != null">#{thirdPartyOrderNum},</if>
|
||||
<if test="deptId != null">#{deptId},</if>
|
||||
<if test="orderType != null">#{orderType},</if>
|
||||
<if test="money != null">#{money},</if>
|
||||
<if test="amount != null">#{amount},</if>
|
||||
<if test="remark != null">#{remark},</if>
|
||||
<if test="status != null">#{status},</if>
|
||||
</trim>
|
||||
</insert>
|
||||
|
||||
<update id="updateAiChargeRefundOrder" parameterType="AiChargeRefundOrder">
|
||||
update ai_charge_refund_order
|
||||
<trim prefix="SET" suffixOverrides=",">
|
||||
<if test="delFlag != null and delFlag != ''">del_flag = #{delFlag},</if>
|
||||
<if test="createBy != null">create_by = #{createBy},</if>
|
||||
<if test="createTime != null">create_time = #{createTime},</if>
|
||||
<if test="updateTime != null">update_time = #{updateTime},</if>
|
||||
<if test="orderNum != null and orderNum != ''">order_num = #{orderNum},</if>
|
||||
<if test="thirdPartyOrderNum != null">third_party_order_num = #{thirdPartyOrderNum},</if>
|
||||
<if test="deptId != null">dept_id = #{deptId},</if>
|
||||
<if test="orderType != null">order_type = #{orderType},</if>
|
||||
<if test="money != null">money = #{money},</if>
|
||||
<if test="amount != null">amount = #{amount},</if>
|
||||
<if test="remark != null">remark = #{remark},</if>
|
||||
<if test="status != null">status = #{status},</if>
|
||||
</trim>
|
||||
where id = #{id}
|
||||
</update>
|
||||
|
||||
<delete id="deleteAiChargeRefundOrderById" parameterType="Long">
|
||||
delete from ai_charge_refund_order where id = #{id}
|
||||
</delete>
|
||||
|
||||
<delete id="deleteAiChargeRefundOrderByIds" parameterType="String">
|
||||
delete from ai_charge_refund_order where id in
|
||||
<foreach item="id" collection="array" open="(" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
</delete>
|
||||
</mapper>
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.ruoyi.ai.mapper.AiDeptArkConfigMapper">
|
||||
|
||||
<resultMap type="AiDeptArkConfig" id="AiDeptArkConfigResult">
|
||||
<result property="id" column="id" />
|
||||
<result property="deptId" column="dept_id" />
|
||||
<result property="modelParm" column="model_parm" />
|
||||
<result property="project" column="project" />
|
||||
<result property="byteApiKey" column="byte_api_key" />
|
||||
<result property="createBy" column="create_by" />
|
||||
<result property="createTime" column="create_time" />
|
||||
<result property="updateBy" column="update_by" />
|
||||
<result property="updateTime" column="update_time" />
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectAiDeptArkConfigVo">
|
||||
select id, dept_id, model_parm, project, byte_api_key, create_by, create_time, update_by, update_time from ai_dept_ark_config
|
||||
</sql>
|
||||
|
||||
<select id="selectAiDeptArkConfigList" parameterType="AiDeptArkConfig" resultMap="AiDeptArkConfigResult">
|
||||
<include refid="selectAiDeptArkConfigVo"/>
|
||||
<where>
|
||||
<if test="deptId != null "> and dept_id = #{deptId}</if>
|
||||
<if test="modelParm != null and modelParm != ''"> and model_parm = #{modelParm}</if>
|
||||
<if test="project != null and project != ''"> and project = #{project}</if>
|
||||
<if test="byteApiKey != null and byteApiKey != ''"> and byte_api_key = #{byteApiKey}</if>
|
||||
</where>
|
||||
</select>
|
||||
|
||||
<select id="selectAiDeptArkConfigById" parameterType="String" resultMap="AiDeptArkConfigResult">
|
||||
<include refid="selectAiDeptArkConfigVo"/>
|
||||
where id = #{id}
|
||||
</select>
|
||||
|
||||
<insert id="insertAiDeptArkConfig" parameterType="AiDeptArkConfig" useGeneratedKeys="true" keyProperty="id">
|
||||
insert into ai_dept_ark_config
|
||||
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||
<if test="deptId != null">dept_id,</if>
|
||||
<if test="modelParm != null">model_parm,</if>
|
||||
<if test="project != null">project,</if>
|
||||
<if test="byteApiKey != null">byte_api_key,</if>
|
||||
<if test="createBy != null">create_by,</if>
|
||||
<if test="createTime != null">create_time,</if>
|
||||
<if test="updateBy != null">update_by,</if>
|
||||
<if test="updateTime != null">update_time,</if>
|
||||
</trim>
|
||||
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
||||
<if test="deptId != null">#{deptId},</if>
|
||||
<if test="modelParm != null">#{modelParm},</if>
|
||||
<if test="project != null">#{project},</if>
|
||||
<if test="byteApiKey != null">#{byteApiKey},</if>
|
||||
<if test="createBy != null">#{createBy},</if>
|
||||
<if test="createTime != null">#{createTime},</if>
|
||||
<if test="updateBy != null">#{updateBy},</if>
|
||||
<if test="updateTime != null">#{updateTime},</if>
|
||||
</trim>
|
||||
</insert>
|
||||
|
||||
<update id="updateAiDeptArkConfig" parameterType="AiDeptArkConfig">
|
||||
update ai_dept_ark_config
|
||||
<trim prefix="SET" suffixOverrides=",">
|
||||
<if test="deptId != null">dept_id = #{deptId},</if>
|
||||
<if test="modelParm != null">model_parm = #{modelParm},</if>
|
||||
<if test="project != null">project = #{project},</if>
|
||||
<if test="byteApiKey != null">byte_api_key = #{byteApiKey},</if>
|
||||
<if test="createBy != null">create_by = #{createBy},</if>
|
||||
<if test="createTime != null">create_time = #{createTime},</if>
|
||||
<if test="updateBy != null">update_by = #{updateBy},</if>
|
||||
<if test="updateTime != null">update_time = #{updateTime},</if>
|
||||
</trim>
|
||||
where id = #{id}
|
||||
</update>
|
||||
|
||||
<delete id="deleteAiDeptArkConfigById" parameterType="String">
|
||||
delete from ai_dept_ark_config where id = #{id}
|
||||
</delete>
|
||||
|
||||
<delete id="deleteAiDeptArkConfigByIds" parameterType="String">
|
||||
delete from ai_dept_ark_config where id in
|
||||
<foreach item="id" collection="array" open="(" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
</delete>
|
||||
</mapper>
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.ruoyi.ai.mapper.AiGroupBalanceChangeRecordMapper">
|
||||
|
||||
<resultMap type="AiGroupBalanceChangeRecord" id="AiGroupBalanceChangeRecordResult">
|
||||
<result property="id" column="id" />
|
||||
<result property="relationOrderNo" column="relation_order_no" />
|
||||
<result property="deptId" column="dept_id" />
|
||||
<result property="type" column="type" />
|
||||
<result property="changeAmount" column="change_amount" />
|
||||
<result property="resultAmount" column="result_amount" />
|
||||
<result property="remark" column="remark" />
|
||||
<result property="createTime" column="create_time" />
|
||||
<result property="updateTime" column="update_time" />
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectAiGroupBalanceChangeRecordVo">
|
||||
select id, relation_order_no, dept_id, type, change_amount, result_amount, remark, create_time, update_time from ai_group_balance_change_record
|
||||
</sql>
|
||||
|
||||
<select id="selectAiGroupBalanceChangeRecordList" parameterType="AiGroupBalanceChangeRecord" resultMap="AiGroupBalanceChangeRecordResult">
|
||||
<include refid="selectAiGroupBalanceChangeRecordVo"/>
|
||||
<where>
|
||||
<if test="relationOrderNo != null and relationOrderNo != ''"> and relation_order_no = #{relationOrderNo}</if>
|
||||
<if test="deptId != null "> and dept_id = #{deptId}</if>
|
||||
<if test="type != null "> and type = #{type}</if>
|
||||
<if test="changeAmount != null "> and change_amount = #{changeAmount}</if>
|
||||
<if test="resultAmount != null "> and result_amount = #{resultAmount}</if>
|
||||
</where>
|
||||
</select>
|
||||
|
||||
<select id="selectAiGroupBalanceChangeRecordById" parameterType="String" resultMap="AiGroupBalanceChangeRecordResult">
|
||||
<include refid="selectAiGroupBalanceChangeRecordVo"/>
|
||||
where id = #{id}
|
||||
</select>
|
||||
|
||||
<insert id="insertAiGroupBalanceChangeRecord" parameterType="AiGroupBalanceChangeRecord" useGeneratedKeys="true" keyProperty="id">
|
||||
insert into ai_group_balance_change_record
|
||||
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||
<if test="relationOrderNo != null">relation_order_no,</if>
|
||||
<if test="deptId != null">dept_id,</if>
|
||||
<if test="type != null">type,</if>
|
||||
<if test="changeAmount != null">change_amount,</if>
|
||||
<if test="resultAmount != null">result_amount,</if>
|
||||
<if test="remark != null">remark,</if>
|
||||
<if test="createTime != null">create_time,</if>
|
||||
<if test="updateTime != null">update_time,</if>
|
||||
</trim>
|
||||
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
||||
<if test="relationOrderNo != null">#{relationOrderNo},</if>
|
||||
<if test="deptId != null">#{deptId},</if>
|
||||
<if test="type != null">#{type},</if>
|
||||
<if test="changeAmount != null">#{changeAmount},</if>
|
||||
<if test="resultAmount != null">#{resultAmount},</if>
|
||||
<if test="remark != null">#{remark},</if>
|
||||
<if test="createTime != null">#{createTime},</if>
|
||||
<if test="updateTime != null">#{updateTime},</if>
|
||||
</trim>
|
||||
</insert>
|
||||
|
||||
<update id="updateAiGroupBalanceChangeRecord" parameterType="AiGroupBalanceChangeRecord">
|
||||
update ai_group_balance_change_record
|
||||
<trim prefix="SET" suffixOverrides=",">
|
||||
<if test="relationOrderNo != null">relation_order_no = #{relationOrderNo},</if>
|
||||
<if test="deptId != null">dept_id = #{deptId},</if>
|
||||
<if test="type != null">type = #{type},</if>
|
||||
<if test="changeAmount != null">change_amount = #{changeAmount},</if>
|
||||
<if test="resultAmount != null">result_amount = #{resultAmount},</if>
|
||||
<if test="remark != null">remark = #{remark},</if>
|
||||
<if test="createTime != null">create_time = #{createTime},</if>
|
||||
<if test="updateTime != null">update_time = #{updateTime},</if>
|
||||
</trim>
|
||||
where id = #{id}
|
||||
</update>
|
||||
|
||||
<delete id="deleteAiGroupBalanceChangeRecordById" parameterType="String">
|
||||
delete from ai_group_balance_change_record where id = #{id}
|
||||
</delete>
|
||||
|
||||
<delete id="deleteAiGroupBalanceChangeRecordByIds" parameterType="String">
|
||||
delete from ai_group_balance_change_record where id in
|
||||
<foreach item="id" collection="array" open="(" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
</delete>
|
||||
</mapper>
|
||||
|
|
@ -0,0 +1,161 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.ruoyi.ai.mapper.AiVideoReportDataMapper">
|
||||
|
||||
<resultMap type="AiVideoReportData" id="AiVideoReportDataResult">
|
||||
<result property="id" column="id" />
|
||||
<result property="dateKey" column="date_key" />
|
||||
<result property="deptId" column="dept_id" />
|
||||
<result property="userId" column="user_id" />
|
||||
<result property="score" column="score" />
|
||||
<result property="orderCount" column="order_count" />
|
||||
<result property="useTokens" column="use_tokens" />
|
||||
<result property="rechargeScore" column="recharge_score" />
|
||||
<result property="deptName" column="dept_name" />
|
||||
<result property="createTime" column="create_time" />
|
||||
<result property="updateTime" column="update_time" />
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectAiVideoReportDataVo">
|
||||
select id, date_key, dept_id, user_id, score, order_count, use_tokens, recharge_score, create_time, update_time from ai_video_report_data
|
||||
</sql>
|
||||
|
||||
<select id="selectAiVideoReportDataList" parameterType="AiVideoReportData" resultMap="AiVideoReportDataResult">
|
||||
<include refid="selectAiVideoReportDataVo"/>
|
||||
<where>
|
||||
<if test="dateKey != null and dateKey != ''"> and date_key = #{dateKey}</if>
|
||||
<if test="deptId != null "> and dept_id = #{deptId}</if>
|
||||
<if test="userId != null "> and user_id = #{userId}</if>
|
||||
<if test="score != null "> and score = #{score}</if>
|
||||
<if test="orderCount != null "> and order_count = #{orderCount}</if>
|
||||
<if test="useTokens != null "> and use_tokens = #{useTokens}</if>
|
||||
<if test="rechargeScore != null "> and recharge_score = #{rechargeScore}</if>
|
||||
</where>
|
||||
</select>
|
||||
|
||||
<select id="selectAiVideoReportDataById" parameterType="String" resultMap="AiVideoReportDataResult">
|
||||
<include refid="selectAiVideoReportDataVo"/>
|
||||
where id = #{id}
|
||||
</select>
|
||||
|
||||
<insert id="insertAiVideoReportData" parameterType="AiVideoReportData" useGeneratedKeys="true" keyProperty="id">
|
||||
insert into ai_video_report_data
|
||||
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||
<if test="dateKey != null and dateKey != ''">date_key,</if>
|
||||
<if test="deptId != null">dept_id,</if>
|
||||
<if test="userId != null">user_id,</if>
|
||||
<if test="score != null">score,</if>
|
||||
<if test="orderCount != null">order_count,</if>
|
||||
<if test="useTokens != null">use_tokens,</if>
|
||||
<if test="rechargeScore != null">recharge_score,</if>
|
||||
<if test="createTime != null">create_time,</if>
|
||||
<if test="updateTime != null">update_time,</if>
|
||||
</trim>
|
||||
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
||||
<if test="dateKey != null and dateKey != ''">#{dateKey},</if>
|
||||
<if test="deptId != null">#{deptId},</if>
|
||||
<if test="userId != null">#{userId},</if>
|
||||
<if test="score != null">#{score},</if>
|
||||
<if test="orderCount != null">#{orderCount},</if>
|
||||
<if test="useTokens != null">#{useTokens},</if>
|
||||
<if test="rechargeScore != null">#{rechargeScore},</if>
|
||||
<if test="createTime != null">#{createTime},</if>
|
||||
<if test="updateTime != null">#{updateTime},</if>
|
||||
</trim>
|
||||
</insert>
|
||||
|
||||
<update id="updateAiVideoReportData" parameterType="AiVideoReportData">
|
||||
update ai_video_report_data
|
||||
<trim prefix="SET" suffixOverrides=",">
|
||||
<if test="dateKey != null and dateKey != ''">date_key = #{dateKey},</if>
|
||||
<if test="deptId != null">dept_id = #{deptId},</if>
|
||||
<if test="userId != null">user_id = #{userId},</if>
|
||||
<if test="score != null">score = #{score},</if>
|
||||
<if test="orderCount != null">order_count = #{orderCount},</if>
|
||||
<if test="useTokens != null">use_tokens = #{useTokens},</if>
|
||||
<if test="rechargeScore != null">recharge_score = #{rechargeScore},</if>
|
||||
<if test="createTime != null">create_time = #{createTime},</if>
|
||||
<if test="updateTime != null">update_time = #{updateTime},</if>
|
||||
</trim>
|
||||
where id = #{id}
|
||||
</update>
|
||||
|
||||
<select id="selectTeamDailyConsumeList" resultMap="AiVideoReportDataResult">
|
||||
select
|
||||
concat(substr(vrd.date_key, 1, 4), '-', substr(vrd.date_key, 5, 2), '-', substr(vrd.date_key, 7, 2)) as date_key,
|
||||
vrd.dept_id,
|
||||
d.dept_name,
|
||||
sum(vrd.recharge_score) as recharge_score,
|
||||
sum(vrd.score) as score,
|
||||
sum(vrd.order_count) as order_count,
|
||||
sum(vrd.use_tokens) as use_tokens
|
||||
from ai_video_report_data vrd
|
||||
left join sys_dept d on d.dept_id = vrd.dept_id
|
||||
where vrd.date_key like concat(#{statDate}, '%')
|
||||
and vrd.dept_id = #{deptId}
|
||||
group by substr(vrd.date_key, 1, 8), vrd.dept_id, d.dept_name
|
||||
order by substr(vrd.date_key, 1, 8) desc, vrd.dept_id desc
|
||||
</select>
|
||||
|
||||
<select id="selectTeamDailyConsumeByDeptId" resultMap="AiVideoReportDataResult">
|
||||
select
|
||||
concat(substr(vrd.date_key, 1, 4), '-', substr(vrd.date_key, 5, 2), '-', substr(vrd.date_key, 7, 2)) as date_key,
|
||||
vrd.dept_id,
|
||||
d.dept_name,
|
||||
sum(vrd.recharge_score) as recharge_score,
|
||||
sum(vrd.score) as score,
|
||||
sum(vrd.order_count) as order_count,
|
||||
sum(vrd.use_tokens) as use_tokens
|
||||
from ai_video_report_data vrd
|
||||
left join sys_dept d on d.dept_id = vrd.dept_id
|
||||
where vrd.date_key like concat(#{statDate}, '%')
|
||||
and vrd.dept_id = #{deptId}
|
||||
group by substr(vrd.date_key, 1, 8), vrd.dept_id, d.dept_name
|
||||
order by substr(vrd.date_key, 1, 8) desc, vrd.dept_id desc
|
||||
</select>
|
||||
|
||||
<select id="selectDeptVideoMetricsBetween" resultType="com.ruoyi.system.domain.subteam.SubteamVideoMetrics">
|
||||
select
|
||||
coalesce(sum(vrd.score), 0) as consumeScore,
|
||||
coalesce(sum(vrd.order_count), 0) as orderCount
|
||||
from ai_video_report_data vrd
|
||||
where vrd.dept_id = #{deptId}
|
||||
and substr(vrd.date_key, 1, 8) >= #{startDay}
|
||||
and substr(vrd.date_key, 1, 8) <= #{endDay}
|
||||
</select>
|
||||
|
||||
<insert id="upsertVideoConsumeIncrement">
|
||||
insert into ai_video_report_data
|
||||
(date_key, dept_id, user_id, score, order_count, use_tokens, recharge_score, create_time, update_time)
|
||||
values
|
||||
(#{dateKey}, #{deptId}, #{userId}, #{score}, #{orderCount}, #{useTokens}, 0, now(), now())
|
||||
on duplicate key update
|
||||
score = score + values(score),
|
||||
order_count = order_count + values(order_count),
|
||||
use_tokens = use_tokens + values(use_tokens),
|
||||
update_time = now()
|
||||
</insert>
|
||||
|
||||
<insert id="upsertRechargeScoreIncrement">
|
||||
insert into ai_video_report_data
|
||||
(date_key, dept_id, user_id, score, order_count, use_tokens, recharge_score, create_time, update_time)
|
||||
values
|
||||
(#{dateKey}, #{deptId}, 0, 0, 0, 0, #{rechargeScore}, now(), now())
|
||||
on duplicate key update
|
||||
recharge_score = recharge_score + values(recharge_score),
|
||||
update_time = now()
|
||||
</insert>
|
||||
|
||||
<delete id="deleteAiVideoReportDataById" parameterType="String">
|
||||
delete from ai_video_report_data where id = #{id}
|
||||
</delete>
|
||||
|
||||
<delete id="deleteAiVideoReportDataByIds" parameterType="String">
|
||||
delete from ai_video_report_data where id in
|
||||
<foreach item="id" collection="array" open="(" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
</delete>
|
||||
</mapper>
|
||||
|
|
@ -43,6 +43,26 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||
</where>
|
||||
order by r.id desc
|
||||
</select>
|
||||
|
||||
<select id="selectAiBalanceChangeRecordListByAiUserDept" resultMap="AiBalanceChangeRecordResult">
|
||||
<include refid="selectAiBalanceChangeRecordVo"/>
|
||||
<where>
|
||||
and u.dept_id = #{deptId}
|
||||
<if test="q.nickname != null and q.nickname != '' "> and u.nickname like concat('%', #{q.nickname}, '%') </if>
|
||||
<if test="q.userId != null "> and r.user_id = #{q.userId}</if>
|
||||
<if test="q.uuid != null "> and u.user_id = #{q.uuid}</if>
|
||||
<if test="q.type != null "> and r.type = #{q.type}</if>
|
||||
<if test="q.changeAmount != null "> and r.change_amount = #{q.changeAmount}</if>
|
||||
<if test="q.resultAmount != null "> and r.result_amount = #{q.resultAmount}</if>
|
||||
<if test="q.params != null and q.params.beginTime != null and q.params.beginTime != ''">
|
||||
AND date_format(r.create_time,'%Y%m%d') >= date_format(#{q.params.beginTime},'%Y%m%d')
|
||||
</if>
|
||||
<if test="q.params != null and q.params.endTime != null and q.params.endTime != ''">
|
||||
AND date_format(r.create_time,'%Y%m%d') <= date_format(#{q.params.endTime},'%Y%m%d')
|
||||
</if>
|
||||
</where>
|
||||
order by r.id desc
|
||||
</select>
|
||||
|
||||
<select id="selectAiBalanceChangeRecordById" parameterType="Long" resultMap="AiBalanceChangeRecordResult">
|
||||
<include refid="selectAiBalanceChangeRecordVo"/>
|
||||
|
|
|
|||
|
|
@ -92,7 +92,4 @@ CREATE TABLE `ai_charge_refund_order` (
|
|||
)
|
||||
COMMENT='团队(部门)充值退款订单表'
|
||||
COLLATE='utf8mb4_unicode_ci'
|
||||
ENGINE=InnoDB;
|
||||
|
||||
ALTER TABLE `ai_user`
|
||||
ADD INDEX `dept_id` (`dept_id`);
|
||||
ENGINE=InnoDB;
|
||||
|
|
@ -193,3 +193,5 @@ values('团队(部门)对应火山引擎配置删除', @parentId, '4', '#',
|
|||
insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
|
||||
values('团队(部门)对应火山引擎配置导出', @parentId, '5', '#', '', 1, 0, 'F', '0', '0', 'ai:config:export', '#', 'admin', sysdate(), '', null, '');
|
||||
|
||||
ALTER TABLE `byteai`.`ai_balance_change_record`
|
||||
ADD COLUMN `dept_id` bigint NULL COMMENT '部门ID' AFTER `remark`;
|
||||
Loading…
Reference in New Issue