Compare commits

..

6 Commits

Author SHA1 Message Date
old burden 15f5a20f7c fix: 仿照即梦出一版 2026-03-31 13:49:46 +08:00
old burden 45cff6ab27 fix: bug修改 result 写成 URL 2026-03-30 13:25:52 +08:00
old burden 8436c3515c fix: 页面优化,工具栏显示 2026-03-30 13:05:04 +08:00
old burden fc1ecf7bc9 fix: bug修改字段缺失 2026-03-30 12:30:04 +08:00
old burden 0f112c019d fix: 参数选择改到参数文件 2026-03-30 12:06:45 +08:00
old burden a69ae255c9 fix: 新页面 2026-03-30 11:07:33 +08:00
29 changed files with 1226 additions and 69 deletions

2
.gitignore vendored
View File

@ -4,7 +4,7 @@
.gradle .gradle
/build/ /build/
!gradle/wrapper/gradle-wrapper.jar !gradle/wrapper/gradle-wrapper.jar
*.sql
target/ target/
!.mvn/wrapper/maven-wrapper.jar !.mvn/wrapper/maven-wrapper.jar

View File

@ -51,6 +51,9 @@ public class AiManagerApiController extends BaseController {
@Anonymous @Anonymous
public AjaxResult selectInfo(String aiType) { public AjaxResult selectInfo(String aiType) {
AiManager aiManager = aiManagerService.selectAiManagerByType(aiType); AiManager aiManager = aiManagerService.selectAiManagerByType(aiType);
if (aiManager == null) {
return AjaxResult.error("该功能未配置或已停用");
}
aiManager.setPrompt(null); aiManager.setPrompt(null);
return AjaxResult.success(aiManager); return AjaxResult.success(aiManager);
} }

View File

@ -93,12 +93,7 @@ public class ByteApiController extends BaseController {
return AjaxResult.error(-1, "You have a low balance, please recharge"); return AjaxResult.error(-1, "You have a low balance, please recharge");
} }
aiOrder.setText(text); aiOrder.setText(text);
aiOrder.setFunctionType(mode); // 记录生成模式 aiOrder.setMode(mode); // 记录生成模式
// 文生视频模式下不设置图片
if ("image-to-video".equals(mode) && firstUrl != null) {
aiOrder.setImg1(firstUrl.toString());
}
ByteBodyReq byteBodyReq = new ByteBodyReq(); ByteBodyReq byteBodyReq = new ByteBodyReq();
// model由前端传入默认为Seedance 2.0 // model由前端传入默认为Seedance 2.0

View File

@ -0,0 +1,38 @@
package com.ruoyi.api;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.TencentCosUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
/**
* COS 上传兼容接口
*/
@RestController
@RequestMapping("/api/cos")
@Api(tags = "COS文件上传")
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class CosController {
private final TencentCosUtil tencentCosUtil;
@ApiOperation("COS上传接口")
@PostMapping("/upload")
public AjaxResult upload(
@ApiParam(name = "file", value = "文件", required = true)
@RequestParam("file") MultipartFile file) throws Exception {
String uploadUrl = tencentCosUtil.uploadMultipartFile(file, true);
AjaxResult ajax = AjaxResult.success(uploadUrl);
ajax.put("url", uploadUrl);
ajax.put("oldName", file.getOriginalFilename());
return ajax;
}
}

View File

@ -0,0 +1,455 @@
package com.ruoyi.api;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.ruoyi.ai.domain.AiOrder;
import com.ruoyi.ai.domain.ByteBodyReq;
import com.ruoyi.ai.domain.ByteBodyRes;
import com.ruoyi.ai.domain.ContentItem;
import com.ruoyi.ai.domain.ImageUrl;
import com.ruoyi.ai.domain.content;
import com.ruoyi.ai.service.IAiOrderService;
import com.ruoyi.ai.service.IByteDeptApiKeyService;
import com.ruoyi.ai.service.IByteService;
import com.ruoyi.api.request.PortalVideoGenRequest;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.TencentCosUtil;
import com.ruoyi.config.PortalVideoProperties;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
/**
* 门户视频生成按用户二级部门 byte_api_key 调用火山任务列表含库表与火山过滤列表
*/
@Api(tags = "门户-视频生成")
@RestController
@RequestMapping("/api/portal/video")
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class PortalVideoController extends BaseController {
private final IByteService byteService;
private final IByteDeptApiKeyService byteDeptApiKeyService;
private final IAiOrderService aiOrderService;
private final TencentCosUtil tencentCosUtil;
private final PortalVideoProperties portalVideoProperties;
@Value("${volcengine.ark.callbackUrl:}")
private String volcCallbackUrl;
private static final ObjectMapper OM = new ObjectMapper();
private String apiKey() {
return byteDeptApiKeyService.resolveVolcApiKey(SecurityUtils.getAiUserId());
}
/** 与 ai_manager.type、portal.video.function-type 对齐,用于扣费 */
private String resolveFunctionType(PortalVideoGenRequest req) {
if (StringUtils.isNotEmpty(req.getFunctionType())) {
return req.getFunctionType();
}
if (StringUtils.isNotEmpty(portalVideoProperties.getFunctionType())) {
return portalVideoProperties.getFunctionType();
}
return "21";
}
private void applyOptionalParams(ByteBodyReq body, PortalVideoGenRequest req) {
PortalVideoProperties.Defaults d = portalVideoProperties.getDefaults();
body.setDuration(req.getDuration() != null ? req.getDuration() : d.getDuration());
body.setResolution(StringUtils.isNotEmpty(req.getResolution()) ? req.getResolution() : d.getResolution());
body.setRatio(StringUtils.isNotEmpty(req.getRatio()) ? req.getRatio() : d.getRatio());
if (StringUtils.isNotEmpty(volcCallbackUrl)) {
body.setCallback_url(volcCallbackUrl);
}
}
private ByteBodyReq newVideoBody(PortalVideoGenRequest req, List<ContentItem> content) {
String modelId = StringUtils.isNotEmpty(req.getModel()) ? req.getModel() : portalVideoProperties.resolveDefaultModelId();
if (StringUtils.isEmpty(modelId)) {
throw new ServiceException("未配置门户视频模型,请在 application.yml 的 portal.video 中配置 models 与 defaults.model");
}
ByteBodyReq body = new ByteBodyReq();
body.setModel(modelId);
body.setContent(content);
applyOptionalParams(body, req);
return body;
}
private void applyOrderImages(AiOrder aiOrder, PortalVideoGenRequest req) {
if (StringUtils.isNotEmpty(req.getFirstUrl())) {
aiOrder.setImg1(req.getFirstUrl());
}
if (StringUtils.isNotEmpty(req.getLastUrl())) {
aiOrder.setImg2(req.getLastUrl());
}
if (StringUtils.isNotEmpty(req.getReferenceUrl())) {
aiOrder.setImg1(req.getReferenceUrl());
}
}
/**
* 写入订单提示词生成模式图床 URL以及模型/时长/分辨率/比例与完整 JSON 参数便于对账与审计
*/
private void fillVideoOrderRecord(AiOrder aiOrder, PortalVideoGenRequest req, String mode, ByteBodyReq body, String functionTypeResolved) {
aiOrder.setText(req.getText());
aiOrder.setMode(mode);
applyOrderImages(aiOrder, req);
if (req.getDuration() != null) {
aiOrder.setDuration(req.getDuration());
} else if (body.getDuration() != null) {
aiOrder.setDuration(body.getDuration());
}
if (StringUtils.isNotEmpty(body.getResolution())) {
aiOrder.setResolution(body.getResolution());
}
if (StringUtils.isNotEmpty(body.getRatio())) {
aiOrder.setRatio(body.getRatio());
}
if (StringUtils.isNotEmpty(body.getModel())) {
aiOrder.setModel(body.getModel());
}
try {
Map<String, Object> snap = new LinkedHashMap<>();
snap.put("generationMode", mode);
snap.put("prompt", req.getText());
snap.put("functionType", functionTypeResolved);
snap.put("model", body.getModel());
snap.put("duration", body.getDuration());
snap.put("resolution", body.getResolution());
snap.put("ratio", body.getRatio());
if (StringUtils.isNotEmpty(req.getFirstUrl())) {
snap.put("firstUrl", req.getFirstUrl());
}
if (StringUtils.isNotEmpty(req.getLastUrl())) {
snap.put("lastUrl", req.getLastUrl());
}
if (StringUtils.isNotEmpty(req.getReferenceUrl())) {
snap.put("referenceUrl", req.getReferenceUrl());
}
if (req.getContent() != null && !req.getContent().isEmpty()) {
snap.put("content", req.getContent());
}
aiOrder.setVideoParams(OM.writeValueAsString(snap));
} catch (Exception e) {
aiOrder.setVideoParams("{\"error\":\"video_params_serialize_failed\"}");
}
}
/** 写入 video_params.volcTaskId任务成功后 result 会改为成品 URL仍应用此 id 校验归属与轮询 */
private void mergeVolcTaskIdIntoVideoParams(AiOrder aiOrder, String volcTaskId) {
if (StringUtils.isEmpty(volcTaskId)) {
return;
}
try {
ObjectNode node;
if (StringUtils.isNotEmpty(aiOrder.getVideoParams())) {
JsonNode existing = OM.readTree(aiOrder.getVideoParams());
if (existing instanceof ObjectNode) {
node = (ObjectNode) existing;
} else {
node = OM.createObjectNode();
node.set("snapshotBeforeVolcId", existing);
}
} else {
node = OM.createObjectNode();
}
node.put("volcTaskId", volcTaskId);
aiOrder.setVideoParams(OM.writeValueAsString(node));
} catch (Exception e) {
aiOrder.setVideoParams("{\"volcTaskId\":\"" + volcTaskId.replace("\"", "") + "\"}");
}
}
private AjaxResult submitOrderAndCreate(PortalVideoGenRequest req, String mode, ByteBodyReq byteBodyReq) {
String functionType = resolveFunctionType(req);
AiOrder aiOrder = aiOrderService.getAiOrder(functionType);
if (aiOrder == null) {
return AjaxResult.error(-1, "You have a low balance, please recharge");
}
try {
fillVideoOrderRecord(aiOrder, req, mode, byteBodyReq, functionType);
aiOrderService.updateAiOrder(aiOrder);
String key = apiKey();
ByteBodyRes byteBodyRes = byteService.imgToVideo(byteBodyReq, key);
String id = byteBodyRes.getId();
if (id == null) {
aiOrderService.orderFailure(aiOrder);
return AjaxResult.error(-2, "generation failed, balance has been refunded");
}
mergeVolcTaskIdIntoVideoParams(aiOrder, id);
aiOrder.setResult(id);
aiOrderService.orderSuccess(aiOrder);
return AjaxResult.success(byteBodyRes);
} catch (Exception e) {
aiOrderService.orderFailure(aiOrder);
throw new RuntimeException(e);
}
}
@PostMapping("/text-to-video")
@ApiOperation("文生视频")
public AjaxResult textToVideo(@RequestBody PortalVideoGenRequest request) {
List<ContentItem> contentList;
if (request.getContent() != null && !request.getContent().isEmpty()) {
contentList = request.getContent();
} else {
if (StringUtils.isEmpty(request.getText())) {
return AjaxResult.error("请输入视频描述文本");
}
contentList = new ArrayList<>();
ContentItem textItem = new ContentItem();
textItem.setType("text");
textItem.setText(request.getText());
contentList.add(textItem);
}
ByteBodyReq body = newVideoBody(request, contentList);
return submitOrderAndCreate(request, "text-to-video", body);
}
@PostMapping("/image-first-frame")
@ApiOperation("图生视频-基于首帧")
public AjaxResult imageFirstFrame(@RequestBody PortalVideoGenRequest request) {
if (StringUtils.isEmpty(request.getFirstUrl())) {
return AjaxResult.error("请上传首帧图片");
}
if (StringUtils.isEmpty(request.getText())) {
return AjaxResult.error("请输入视频描述文本");
}
List<ContentItem> contentList = buildTextAndFirstFrame(request.getText(), request.getFirstUrl());
ByteBodyReq body = newVideoBody(request, contentList);
return submitOrderAndCreate(request, "image-first-frame", body);
}
@PostMapping("/image-first-last-frame")
@ApiOperation("图生视频-基于首尾帧")
public AjaxResult imageFirstLastFrame(@RequestBody PortalVideoGenRequest request) {
if (StringUtils.isEmpty(request.getFirstUrl()) || StringUtils.isEmpty(request.getLastUrl())) {
return AjaxResult.error("请同时上传首帧与尾帧图片");
}
if (StringUtils.isEmpty(request.getText())) {
return AjaxResult.error("请输入视频描述文本");
}
List<ContentItem> contentList = buildTextAndFirstFrame(request.getText(), request.getFirstUrl());
ContentItem lastFrameItem = new ContentItem();
lastFrameItem.setType("image_url");
lastFrameItem.setRole("last_frame");
ImageUrl lastImageUrl = new ImageUrl();
lastImageUrl.setUrl(request.getLastUrl());
lastFrameItem.setImageUrl(lastImageUrl);
contentList.add(lastFrameItem);
ByteBodyReq body = newVideoBody(request, contentList);
return submitOrderAndCreate(request, "image-first-last-frame", body);
}
@PostMapping("/image-reference")
@ApiOperation("图生视频-基于参考图")
public AjaxResult imageReference(@RequestBody PortalVideoGenRequest request) {
List<ContentItem> contentList;
if (request.getContent() != null && !request.getContent().isEmpty()) {
contentList = request.getContent();
ContentItem head = contentList.get(0);
if (head == null || !"text".equals(head.getType()) || StringUtils.isEmpty(head.getText())) {
return AjaxResult.error("请输入视频描述文本(首条须为 type=text可含 [图n] 占位)");
}
String firstRef = contentList.stream()
.filter(PortalVideoController::isReferenceImageContentItem)
.map(it -> it.getImageUrl().getUrl())
.findFirst()
.orElse(null);
if (StringUtils.isEmpty(firstRef)) {
return AjaxResult.error("请上传参考图content 中须含 image_url + role=reference_image");
}
if (StringUtils.isEmpty(request.getReferenceUrl())) {
request.setReferenceUrl(firstRef);
}
} else {
if (StringUtils.isEmpty(request.getReferenceUrl())) {
return AjaxResult.error("请上传参考图");
}
if (StringUtils.isEmpty(request.getText())) {
return AjaxResult.error("请输入视频描述文本");
}
contentList = new ArrayList<>();
ContentItem textItem = new ContentItem();
textItem.setType("text");
textItem.setText(request.getText());
contentList.add(textItem);
ContentItem refItem = new ContentItem();
refItem.setType("image_url");
refItem.setRole("reference_image");
ImageUrl refUrl = new ImageUrl();
refUrl.setUrl(request.getReferenceUrl());
refItem.setImageUrl(refUrl);
contentList.add(refItem);
}
ByteBodyReq body = newVideoBody(request, contentList);
return submitOrderAndCreate(request, "image-reference", body);
}
private static boolean isReferenceImageContentItem(ContentItem item) {
if (item == null || !"image_url".equals(item.getType())) {
return false;
}
if (!"reference_image".equals(item.getRole())) {
return false;
}
ImageUrl iu = item.getImageUrl();
return iu != null && StringUtils.isNotEmpty(iu.getUrl());
}
private List<ContentItem> buildTextAndFirstFrame(String text, String firstUrl) {
List<ContentItem> contentList = new ArrayList<>();
ContentItem textItem = new ContentItem();
textItem.setType("text");
textItem.setText(text);
contentList.add(textItem);
ContentItem firstFrameItem = new ContentItem();
firstFrameItem.setType("image_url");
firstFrameItem.setRole("first_frame");
ImageUrl firstImageUrl = new ImageUrl();
firstImageUrl.setUrl(firstUrl);
firstFrameItem.setImageUrl(firstImageUrl);
contentList.add(firstFrameItem);
return contentList;
}
@GetMapping("/options")
@ApiOperation("门户视频生成可选参数(模型/比例/时长等,来自配置)")
public AjaxResult videoParamOptions() {
Map<String, Object> data = new LinkedHashMap<>();
data.put("defaults", portalVideoProperties.getDefaults());
data.put("models", portalVideoProperties.getModels());
data.put("ratios", portalVideoProperties.getRatios());
data.put("durations", portalVideoProperties.getDurations());
data.put("resolutions", portalVideoProperties.getResolutions());
return AjaxResult.success(data);
}
@GetMapping("/tasks")
@ApiOperation("查询视频生成任务列表(本用户库表分页)")
public TableDataInfo listMyVideoTasks(AiOrder aiOrder) {
aiOrder.setUserId(SecurityUtils.getAiUserId());
aiOrder.setType("21");
startPage();
List<AiOrder> list = aiOrderService.selectAiOrderList(aiOrder);
return getDataTable(list);
}
@GetMapping("/volc-tasks")
@ApiOperation("查询视频生成任务列表(火山平台,按本用户在库中的任务 id 过滤)")
public AjaxResult listVolcTasks(
@RequestParam(defaultValue = "1") int pageNum,
@RequestParam(defaultValue = "20") int pageSize) throws Exception {
Long uid = SecurityUtils.getAiUserId();
String key = apiKey();
String raw = byteService.listVideoGenerationTasks(pageNum, pageSize, key);
String filtered = filterVolcTasksJsonForUser(raw, uid);
return AjaxResult.success(OM.readTree(filtered));
}
private String filterVolcTasksJsonForUser(String raw, Long userId) throws Exception {
AiOrder query = new AiOrder();
query.setUserId(userId);
query.setType("21");
List<AiOrder> mine = aiOrderService.selectAiOrderList(query);
Set<String> allowed = mine.stream()
.map(AiOrder::getResult)
.filter(StringUtils::isNotEmpty)
.collect(Collectors.toSet());
JsonNode root = OM.readTree(raw);
if (!(root instanceof ObjectNode)) {
return raw;
}
ArrayNode arr = null;
String arrayKey = null;
if (root.has("items") && root.get("items").isArray()) {
arr = (ArrayNode) root.get("items");
arrayKey = "items";
} else if (root.has("data") && root.get("data").isArray()) {
arr = (ArrayNode) root.get("data");
arrayKey = "data";
}
if (arr == null) {
return raw;
}
ArrayNode out = OM.createArrayNode();
for (JsonNode n : arr) {
String tid = n.has("id") ? n.get("id").asText() : null;
if (tid != null && allowed.contains(tid)) {
out.add(n);
}
}
ObjectNode result = ((ObjectNode) root).deepCopy();
result.set(arrayKey, out);
result.put("filtered_total", out.size());
return OM.writeValueAsString(result);
}
@GetMapping("/tasks/{taskId}")
@ApiOperation("查询单个视频生成任务(火山)")
public AjaxResult getVolcTask(@PathVariable String taskId) throws Exception {
Long uid = SecurityUtils.getAiUserId();
AiOrder owned = aiOrderService.getAiOrderByPortalVideoTask(taskId);
if (owned == null || !uid.equals(owned.getUserId())) {
return AjaxResult.error("无权查看该任务");
}
String key = apiKey();
ByteBodyRes byteBodyRes = byteService.uploadVideo(taskId, key);
if ("succeeded".equals(byteBodyRes.getStatus())) {
content contentObj = byteBodyRes.getContent();
if (contentObj != null && StringUtils.isNotEmpty(contentObj.getVideo_url())) {
String videoUrl = tencentCosUtil.uploadFileByUrl(contentObj.getVideo_url());
if (videoUrl != null) {
contentObj.setVideo_url(videoUrl);
AiOrder aiOrder = new AiOrder();
aiOrder.setId(owned.getId());
aiOrder.setResult(videoUrl);
aiOrderService.updateAiOrder(aiOrder);
}
}
}
return AjaxResult.success(byteBodyRes);
}
@DeleteMapping("/tasks/{taskId}")
@ApiOperation("删除或取消视频生成任务")
public AjaxResult deleteOrCancelTask(@PathVariable String taskId) throws Exception {
Long uid = SecurityUtils.getAiUserId();
AiOrder owned = aiOrderService.getAiOrderByPortalVideoTask(taskId);
if (owned == null || !uid.equals(owned.getUserId())) {
return AjaxResult.error("无权操作该任务");
}
String key = apiKey();
AjaxResult cancelRes = byteService.cancelVideoTask(taskId, key);
if (cancelRes.isSuccess() && owned.getStatus() != null && owned.getStatus() == 0) {
aiOrderService.orderFailure(owned);
}
return cancelRes;
}
}

View File

@ -0,0 +1,38 @@
package com.ruoyi.api.request;
import com.ruoyi.ai.domain.ContentItem;
import lombok.Data;
import java.util.List;
/**
* 门户视频生成火山 Seedance请求体
*/
@Data
public class PortalVideoGenRequest {
private String text;
/**
* 文生视频时可选多段文本 + 参考图与火山 content 一致不传则仅使用 text 单行
*/
private List<ContentItem> content;
/** 默认与后台配置的视频计费类型一致 */
private String functionType = "21";
private String model;
private Integer duration;
private String resolution;
private String ratio;
private String firstUrl;
private String lastUrl;
/** 图生视频-参考图模式 */
private String referenceUrl;
}

View File

@ -0,0 +1,153 @@
package com.ruoyi.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
/**
* 门户视频生成参数模型比例时长分辨率等从配置读取不在代码中写死业务默认值
*/
@Component
@ConfigurationProperties(prefix = "portal.video")
public class PortalVideoProperties {
private Defaults defaults = new Defaults();
private List<ModelOption> models = new ArrayList<>();
private List<String> ratios = new ArrayList<>();
private List<Integer> durations = new ArrayList<>();
private List<String> resolutions = new ArrayList<>();
/**
* ai_manager.type 一致用于扣费与订单库中需存在对应记录且 status=0del_flag=0
*/
private String functionType = "21";
public String getFunctionType() {
return functionType;
}
public void setFunctionType(String functionType) {
this.functionType = functionType != null ? functionType : "21";
}
public Defaults getDefaults() {
return defaults;
}
public void setDefaults(Defaults defaults) {
if (defaults != null) {
this.defaults = defaults;
}
}
public List<ModelOption> getModels() {
return models;
}
public void setModels(List<ModelOption> models) {
this.models = models != null ? models : new ArrayList<>();
}
public List<String> getRatios() {
return ratios;
}
public void setRatios(List<String> ratios) {
this.ratios = ratios != null ? ratios : new ArrayList<>();
}
public List<Integer> getDurations() {
return durations;
}
public void setDurations(List<Integer> durations) {
this.durations = durations != null ? durations : new ArrayList<>();
}
public List<String> getResolutions() {
return resolutions;
}
public void setResolutions(List<String> resolutions) {
this.resolutions = resolutions != null ? resolutions : new ArrayList<>();
}
/**
* defaults.model 为空时 models 第一项的 value
*/
public String resolveDefaultModelId() {
if (defaults.getModel() != null && !defaults.getModel().isEmpty()) {
return defaults.getModel();
}
if (!models.isEmpty() && models.get(0).getValue() != null) {
return models.get(0).getValue();
}
return null;
}
public static class Defaults {
private String model;
private Integer duration;
private String resolution;
private String ratio;
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
public Integer getDuration() {
return duration;
}
public void setDuration(Integer duration) {
this.duration = duration;
}
public String getResolution() {
return resolution;
}
public void setResolution(String resolution) {
this.resolution = resolution;
}
public String getRatio() {
return ratio;
}
public void setRatio(String ratio) {
this.ratio = ratio;
}
}
public static class ModelOption {
private String label;
private String value;
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
}

View File

@ -0,0 +1,120 @@
package com.ruoyi.web.controller.ai;
import java.util.List;
import org.apache.commons.lang3.ArrayUtils;
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.ai.service.IAiUserService;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.service.ISysDeptService;
/**
* AI 业务侧部门管理数据源与系统部门 sys_dept 一致权限独立
*/
@RestController
@RequestMapping("/ai/dept")
public class AiDeptController extends BaseController
{
@Autowired
private ISysDeptService deptService;
@Autowired
private IAiUserService aiUserService;
@PreAuthorize("@ss.hasPermi('ai:dept:list')")
@GetMapping("/list")
public AjaxResult list(SysDept dept)
{
List<SysDept> depts = deptService.selectDeptList(dept);
return success(depts);
}
@PreAuthorize("@ss.hasPermi('ai:dept:list')")
@GetMapping("/list/exclude/{deptId}")
public AjaxResult excludeChild(@PathVariable(value = "deptId", required = false) Long deptId)
{
List<SysDept> depts = deptService.selectDeptList(new SysDept());
depts.removeIf(d -> d.getDeptId().intValue() == deptId || ArrayUtils.contains(StringUtils.split(d.getAncestors(), ","), deptId + ""));
return success(depts);
}
@PreAuthorize("@ss.hasPermi('ai:dept:query')")
@GetMapping(value = "/{deptId}")
public AjaxResult getInfo(@PathVariable Long deptId)
{
deptService.checkDeptDataScope(deptId);
return success(deptService.selectDeptById(deptId));
}
@PreAuthorize("@ss.hasPermi('ai:dept:add')")
@Log(title = "AI部门管理", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@Validated @RequestBody SysDept dept)
{
if (!deptService.checkDeptNameUnique(dept))
{
return error("新增部门'" + dept.getDeptName() + "'失败,部门名称已存在");
}
dept.setCreateBy(getUsername());
return toAjax(deptService.insertDept(dept));
}
@PreAuthorize("@ss.hasPermi('ai:dept:edit')")
@Log(title = "AI部门管理", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@Validated @RequestBody SysDept dept)
{
Long deptId = dept.getDeptId();
deptService.checkDeptDataScope(deptId);
if (!deptService.checkDeptNameUnique(dept))
{
return error("修改部门'" + dept.getDeptName() + "'失败,部门名称已存在");
}
else if (dept.getParentId().equals(deptId))
{
return error("修改部门'" + dept.getDeptName() + "'失败,上级部门不能是自己");
}
else if (StringUtils.equals(UserConstants.DEPT_DISABLE, dept.getStatus()) && deptService.selectNormalChildrenDeptById(deptId) > 0)
{
return error("该部门包含未停用的子部门!");
}
dept.setUpdateBy(getUsername());
return toAjax(deptService.updateDept(dept));
}
@PreAuthorize("@ss.hasPermi('ai:dept:remove')")
@Log(title = "AI部门管理", businessType = BusinessType.DELETE)
@DeleteMapping("/{deptId}")
public AjaxResult remove(@PathVariable Long deptId)
{
if (deptService.hasChildByDeptId(deptId))
{
return warn("存在下级部门,不允许删除");
}
if (deptService.checkDeptExistUser(deptId))
{
return warn("部门存在系统用户,不允许删除");
}
if (aiUserService.countAiUserByDeptId(deptId) > 0)
{
return warn("部门存在 AI 用户,不允许删除");
}
deptService.checkDeptDataScope(deptId);
return toAjax(deptService.deleteDeptById(deptId));
}
}

View File

@ -93,6 +93,20 @@ public class AiUserController extends BaseController {
return toAjax(aiUserService.updateAiUser(aiUser)); return toAjax(aiUserService.updateAiUser(aiUser));
} }
/**
* 分配归属部门deptId 为空表示不归属任何部门
*/
@ApiOperation("分配AI用户归属部门")
@PreAuthorize("@ss.hasPermi('ai:user:edit')")
@Log(title = "ai-用户信息", businessType = BusinessType.UPDATE)
@PutMapping("/dept")
public AjaxResult assignDept(@RequestBody AiUser aiUser) {
if (aiUser.getId() == null) {
return error("用户主键不能为空");
}
return toAjax(aiUserService.updateAiUserDept(aiUser.getId(), aiUser.getDeptId()));
}
/** /**
* 状态修改 * 状态修改
*/ */

View File

@ -235,6 +235,42 @@ volcengine:
apiKey: 3e33e034-7e25-4228-8864-b51b2a7a8f97 apiKey: 3e33e034-7e25-4228-8864-b51b2a7a8f97
callbackUrl: https://undressing.top/api/ai/volcCallback callbackUrl: https://undressing.top/api/ai/volcCallback
# 门户视频生成页:模型 / 比例 / 时长 / 分辨率均由此处维护,前后端不写死业务枚举
portal:
video:
# 与库表 ai_manager.type 一致(用于扣费);若报错 functionType does not exist请插入对应 type 或改此处与库一致
function-type: "21"
defaults:
model: ep-20260326165811-dlkth
duration: 4
resolution: 720p
ratio: "3:4"
models:
- label: Seedance 2.0
value: ep-20260326165811-dlkth
- label: Seedance 2.0 Fast
value: ep-20260326170056-dkj9m
ratios:
- "16:9"
- "9:16"
- "3:4"
- "1:1"
- "4:3"
durations:
- 4
- 5
- 6
- 8
- 10
- 11
- 12
- 13
- 14
- 15
resolutions:
- "720p"
- "1080p"
jinsha: jinsha:
url: https://api.jinshapay.xyz url: https://api.jinshapay.xyz
appId: 1763617360 appId: 1763617360

View File

@ -117,12 +117,19 @@ public class AiUser extends BaseEntity {
*/ */
private String country; private String country;
/** 归属部门IDsys_dept.dept_id */
private Long deptId;
/** /**
* 上级用户昵称 * 上级用户昵称
*/ */
@TableField(exist = false) @TableField(exist = false)
private String superiorName; private String superiorName;
/** 归属部门名称 */
@TableField(exist = false)
private String deptName;
/** /**
* 上级用户ID * 上级用户ID
*/ */

View File

@ -51,6 +51,9 @@ public class SysDept extends BaseEntity
/** 父部门名称 */ /** 父部门名称 */
private String parentName; private String parentName;
/** Byte API Key */
private String byteApiKey;
/** 子部门 */ /** 子部门 */
private List<SysDept> children = new ArrayList<SysDept>(); private List<SysDept> children = new ArrayList<SysDept>();
@ -171,6 +174,16 @@ public class SysDept extends BaseEntity
this.parentName = parentName; this.parentName = parentName;
} }
public String getByteApiKey()
{
return byteApiKey;
}
public void setByteApiKey(String byteApiKey)
{
this.byteApiKey = byteApiKey;
}
public List<SysDept> getChildren() public List<SysDept> getChildren()
{ {
return children; return children;
@ -192,6 +205,7 @@ public class SysDept extends BaseEntity
.append("leader", getLeader()) .append("leader", getLeader())
.append("phone", getPhone()) .append("phone", getPhone())
.append("email", getEmail()) .append("email", getEmail())
.append("byteApiKey", getByteApiKey())
.append("status", getStatus()) .append("status", getStatus())
.append("delFlag", getDelFlag()) .append("delFlag", getDelFlag())
.append("createBy", getCreateBy()) .append("createBy", getCreateBy())

View File

@ -84,6 +84,12 @@ public class AiOrder extends BaseEntity {
@Excel(name = "宽高比") @Excel(name = "宽高比")
private String ratio; private String ratio;
/** 火山/方舟模型 endpoint */
private String model;
/** 视频类订单:本次提交的完整参数 JSON提示词、模型、时长等 */
private String videoParams;
/** 首帧图片 */ /** 首帧图片 */
private String img1; private String img1;

View File

@ -22,5 +22,8 @@ public interface AiOrderMapper extends BaseMapper<AiOrder> {
AiOrder getAiOrderByResult(@Param("result") String result); AiOrder getAiOrderByResult(@Param("result") String result);
/** 门户视频:按火山任务 id 查单result 可能已被替换为成品 URL故兼查 video_params.volcTaskId */
AiOrder getAiOrderByPortalVideoTask(@Param("taskId") String taskId);
BigDecimal getSumAmountByUserId(@Param("userId") String userId); BigDecimal getSumAmountByUserId(@Param("userId") String userId);
} }

View File

@ -6,6 +6,7 @@ import java.util.List;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.common.core.domain.entity.AiUser; import com.ruoyi.common.core.domain.entity.AiUser;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Update;
/** /**
* ai-用户信息Mapper接口 * ai-用户信息Mapper接口
@ -22,4 +23,9 @@ public interface AiUserMapper extends BaseMapper<AiUser> {
AiUser selectAiUserById(Long id); AiUser selectAiUserById(Long id);
AiUser getUserInfo(Long id); AiUser getUserInfo(Long id);
int countAiUserByDeptId(@Param("deptId") Long deptId);
@Update("update ai_user set dept_id = #{deptId}, update_time = sysdate() where id = #{userId}")
int updateAiUserDeptId(@Param("userId") Long userId, @Param("deptId") Long deptId);
} }

View File

@ -79,5 +79,7 @@ public interface IAiOrderService {
AiOrder getAiOrderByResult(String result); AiOrder getAiOrderByResult(String result);
AiOrder getAiOrderByPortalVideoTask(String taskId);
BigDecimal getSumAmountByUserId(String userId); BigDecimal getSumAmountByUserId(String userId);
} }

View File

@ -99,6 +99,16 @@ public interface IAiUserService {
int updatePassword(AiUser aiUser); int updatePassword(AiUser aiUser);
/**
* 部门下 AI 用户数量用于删除部门前校验
*/
int countAiUserByDeptId(Long deptId);
/**
* 分配 AI 用户归属部门deptId 为空则清空
*/
int updateAiUserDept(Long userId, Long deptId);
public void deductSampleAmount(String userId); public void deductSampleAmount(String userId);
void handleRebate(String orderNo, Long userId, BigDecimal rechargeAmount); void handleRebate(String orderNo, Long userId, BigDecimal rechargeAmount);

View File

@ -0,0 +1,12 @@
package com.ruoyi.ai.service;
/**
* 门户用户火山方舟 API Key取自所属二级部门 {@code sys_dept.byte_api_key} Redis 缓存
*/
public interface IByteDeptApiKeyService {
/**
* Redis {userId}_byte_api_key优先读缓存再读库均无有效 key 则抛出业务异常
*/
String resolveVolcApiKey(Long aiUserId);
}

View File

@ -17,17 +17,31 @@ public interface IByteService {
ByteBodyRes imgToImg(ByteBodyReq req) throws Exception; ByteBodyRes imgToImg(ByteBodyReq req) throws Exception;
/** /**
* 首尾帧图生视频 * 首尾帧图生视频使用全局配置的 Ark API Key
*/ */
ByteBodyRes imgToVideo(ByteBodyReq req) throws Exception; ByteBodyRes imgToVideo(ByteBodyReq req) throws Exception;
/**
* 视频生成任务创建指定 Ark API Key门户按部门密钥调用
*/
ByteBodyRes imgToVideo(ByteBodyReq req, String arkApiKey) throws Exception;
/** /**
* 下载视频 * 下载视频
*/ */
ByteBodyRes uploadVideo(String id) throws Exception; ByteBodyRes uploadVideo(String id) throws Exception;
ByteBodyRes uploadVideo(String id, String arkApiKey) throws Exception;
/** /**
* 取消视频生成任务 * 取消视频生成任务
*/ */
AjaxResult cancelVideoTask(String id) throws Exception; AjaxResult cancelVideoTask(String id) throws Exception;
AjaxResult cancelVideoTask(String id, String arkApiKey) throws Exception;
/**
* GET 查询视频生成任务列表火山 list 文档返回原始 JSON 字符串
*/
String listVideoGenerationTasks(int pageNum, int pageSize, String arkApiKey) throws Exception;
} }

View File

@ -124,6 +124,8 @@ public class AiManagerServiceImpl implements IAiManagerService {
public AiManager selectAiManagerByType(String aiType) { public AiManager selectAiManagerByType(String aiType) {
QueryWrapper<AiManager> queryWrapper = new QueryWrapper<>(); QueryWrapper<AiManager> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("type", aiType); queryWrapper.eq("type", aiType);
queryWrapper.eq("del_flag", "0");
queryWrapper.eq("status", 0);
return aiManagerMapper.selectOne(queryWrapper); return aiManagerMapper.selectOne(queryWrapper);
} }
} }

View File

@ -147,7 +147,9 @@ public class AiOrderServiceImpl implements IAiOrderService {
public AiOrder getAiOrder(String aiType) { public AiOrder getAiOrder(String aiType) {
AiManager aiManager = aiManagerService.selectAiManagerByType(aiType); AiManager aiManager = aiManagerService.selectAiManagerByType(aiType);
if (aiManager == null) { if (aiManager == null) {
throw new ServiceException("Corresponding functionType does not exist", HttpStatus.BAD_REQUEST); throw new ServiceException(
"未找到可用的功能类型请在「AI管理」中新增 type=" + aiType + " 且状态为正常的记录,或执行 sql/seed_ai_manager_type_21.sql 初始化",
HttpStatus.BAD_REQUEST);
} }
// 判断用户余额是否足够 // 判断用户余额是否足够
AiUser aiUser = aiUserService.selectAiUserById(SecurityUtils.getAiUserId()); AiUser aiUser = aiUserService.selectAiUserById(SecurityUtils.getAiUserId());
@ -201,6 +203,11 @@ public class AiOrderServiceImpl implements IAiOrderService {
return aiOrderMapper.selectOne(query); return aiOrderMapper.selectOne(query);
} }
@Override
public AiOrder getAiOrderByPortalVideoTask(String taskId) {
return aiOrderMapper.getAiOrderByPortalVideoTask(taskId);
}
public int getChangerType(String aiType) { public int getChangerType(String aiType) {
switch (aiType) { switch (aiType) {
case "11": case "11":

View File

@ -132,6 +132,19 @@ public class AiUserServiceImpl implements IAiUserService {
return aiUserMapper.updateById(aiUser); return aiUserMapper.updateById(aiUser);
} }
@Override
public int countAiUserByDeptId(Long deptId) {
if (deptId == null) {
return 0;
}
return aiUserMapper.countAiUserByDeptId(deptId);
}
@Override
public int updateAiUserDept(Long userId, Long deptId) {
return aiUserMapper.updateAiUserDeptId(userId, deptId);
}
/** /**
* 批量删除ai-用户信息 * 批量删除ai-用户信息
* *

View File

@ -0,0 +1,99 @@
package com.ruoyi.ai.service.impl;
import com.ruoyi.ai.service.IByteDeptApiKeyService;
import com.ruoyi.ai.service.IAiUserService;
import com.ruoyi.common.core.domain.entity.AiUser;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.service.ISysDeptService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;
@Service
public class ByteDeptApiKeyServiceImpl implements IByteDeptApiKeyService {
private static final String NO_DEPT_MSG = "用户未分配部门:请在后台为门户用户设置 ai_user.dept_id关联 sys_dept.dept_id";
private static final String NO_DEPT_ROW_MSG = "用户所属部门不存在或已删除,请核对 ai_user.dept_id";
private static final String NO_API_KEY_MSG = "部门未配置火山 API Key请在 sys_dept 为用户所在部门(或其上级二级部门)配置 byte_api_key";
private static final int CACHE_HOURS = 1;
@Autowired
private RedisCache redisCache;
@Autowired
private IAiUserService aiUserService;
@Autowired
private ISysDeptService sysDeptService;
@Override
public String resolveVolcApiKey(Long aiUserId) {
if (aiUserId == null) {
throw new ServiceException(NO_DEPT_MSG);
}
String cacheKey = aiUserId + "_byte_api_key";
String cached = redisCache.getCacheObject(cacheKey);
if (StringUtils.isNotEmpty(cached)) {
return cached;
}
AiUser aiUser = aiUserService.selectAiUserById(aiUserId);
if (aiUser == null || aiUser.getDeptId() == null) {
throw new ServiceException(NO_DEPT_MSG);
}
SysDept userDept = sysDeptService.selectDeptById(aiUser.getDeptId());
if (userDept == null) {
throw new ServiceException(NO_DEPT_ROW_MSG);
}
// 优先使用用户直接归属部门的 Key多数业务把用户挂在分公司 101并在该节点配 byte_api_key
String apiKey = trimKey(userDept.getByteApiKey());
if (StringUtils.isEmpty(apiKey)) {
Long fallbackDeptId = resolveSecondLevelDeptId(userDept);
if (!fallbackDeptId.equals(userDept.getDeptId())) {
SysDept keyDept = sysDeptService.selectDeptById(fallbackDeptId);
if (keyDept != null) {
apiKey = trimKey(keyDept.getByteApiKey());
}
}
}
if (StringUtils.isEmpty(apiKey)) {
throw new ServiceException(NO_API_KEY_MSG);
}
redisCache.setCacheObject(cacheKey, apiKey, CACHE_HOURS, TimeUnit.HOURS);
return apiKey;
}
private static String trimKey(String raw) {
return raw == null ? null : raw.trim();
}
/**
* 二级部门祖级路径中紧接在一级ancestors 第二段之下的部门节点
* 深度不足时退回用户当前部门
*/
private Long resolveSecondLevelDeptId(SysDept userDept) {
String ancestors = userDept.getAncestors();
if (StringUtils.isEmpty(ancestors)) {
return userDept.getDeptId();
}
String[] parts = ancestors.split(",");
if (parts.length >= 3) {
try {
return Long.parseLong(parts[2].trim());
} catch (NumberFormatException ignored) {
return userDept.getDeptId();
}
}
if (parts.length == 2) {
try {
return Long.parseLong(parts[1].trim());
} catch (NumberFormatException ignored) {
return userDept.getDeptId();
}
}
return userDept.getDeptId();
}
}

View File

@ -9,6 +9,7 @@ import com.ruoyi.ai.service.IByteService;
import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.http.OkHttpUtils; import com.ruoyi.common.utils.http.OkHttpUtils;
import okhttp3.HttpUrl;
import okhttp3.*; import okhttp3.*;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -83,17 +84,24 @@ public class ByteService implements IByteService {
@Override @Override
public ByteBodyRes imgToVideo(ByteBodyReq req) throws Exception { public ByteBodyRes imgToVideo(ByteBodyReq req) throws Exception {
return imgToVideo(req, volcApiKey);
}
@Override
public ByteBodyRes imgToVideo(ByteBodyReq req, String arkApiKey) throws Exception {
if (req == null) { if (req == null) {
throw new Exception("imgToVideo errorreq is null"); throw new Exception("imgToVideo errorreq is null");
} }
if (StringUtils.isBlank(arkApiKey)) {
throw new Exception("imgToVideo errorapiKey is null");
}
// 使用火山引擎配置
String jsonBody = objectMapper.writeValueAsString(req); String jsonBody = objectMapper.writeValueAsString(req);
Request request = new Request.Builder() Request request = new Request.Builder()
.url(volcBaseUrl + "/api/v3/contents/generations/tasks") .url(volcBaseUrl + "/api/v3/contents/generations/tasks")
.header("Content-Type", "application/json") .header("Content-Type", "application/json")
.header("Authorization", "Bearer " + volcApiKey) .header("Authorization", "Bearer " + arkApiKey)
.post(RequestBody.create( .post(RequestBody.create(
MediaType.parse("application/json; charset=utf-8"), MediaType.parse("application/json; charset=utf-8"),
jsonBody jsonBody
@ -117,15 +125,22 @@ public class ByteService implements IByteService {
@Override @Override
public ByteBodyRes uploadVideo(String id) throws Exception { public ByteBodyRes uploadVideo(String id) throws Exception {
return uploadVideo(id, volcApiKey);
}
@Override
public ByteBodyRes uploadVideo(String id, String arkApiKey) throws Exception {
if (StringUtils.isBlank(id)) { if (StringUtils.isBlank(id)) {
throw new Exception("uploadVideo errorid is null"); throw new Exception("uploadVideo errorid is null");
} }
if (StringUtils.isBlank(arkApiKey)) {
throw new Exception("uploadVideo errorapiKey is null");
}
// 使用火山引擎配置查询任务状态
Request request = new Request.Builder() Request request = new Request.Builder()
.url(volcBaseUrl + "/api/v3/contents/generations/tasks/" + id) .url(volcBaseUrl + "/api/v3/contents/generations/tasks/" + id)
.header("Content-Type", "application/json") .header("Content-Type", "application/json")
.header("Authorization", "Bearer " + volcApiKey) .header("Authorization", "Bearer " + arkApiKey)
.get() .get()
.build(); .build();
@ -146,16 +161,23 @@ public class ByteService implements IByteService {
@Override @Override
public AjaxResult cancelVideoTask(String id) throws Exception { public AjaxResult cancelVideoTask(String id) throws Exception {
return cancelVideoTask(id, volcApiKey);
}
@Override
public AjaxResult cancelVideoTask(String id, String arkApiKey) throws Exception {
if (StringUtils.isBlank(id)) { if (StringUtils.isBlank(id)) {
return AjaxResult.error("任务ID不能为空"); return AjaxResult.error("任务ID不能为空");
} }
if (StringUtils.isBlank(arkApiKey)) {
return AjaxResult.error("API Key 无效");
}
try { try {
// 向火山引擎发送 DELETE 请求取消任务
Request request = new Request.Builder() Request request = new Request.Builder()
.url(volcBaseUrl + "/api/v3/contents/generations/tasks/" + id) .url(volcBaseUrl + "/api/v3/contents/generations/tasks/" + id)
.header("Content-Type", "application/json") .header("Content-Type", "application/json")
.header("Authorization", "Bearer " + volcApiKey) .header("Authorization", "Bearer " + arkApiKey)
.delete() .delete()
.build(); .build();
@ -171,4 +193,39 @@ public class ByteService implements IByteService {
return AjaxResult.error("取消任务异常:" + e.getMessage()); return AjaxResult.error("取消任务异常:" + e.getMessage());
} }
} }
@Override
public String listVideoGenerationTasks(int pageNum, int pageSize, String arkApiKey) throws Exception {
if (StringUtils.isBlank(arkApiKey)) {
throw new Exception("listVideoGenerationTasks errorapiKey is null");
}
int pn = pageNum > 0 ? pageNum : 1;
int ps = pageSize > 0 ? Math.min(pageSize, 500) : 10;
HttpUrl parsed = HttpUrl.parse(volcBaseUrl + "/api/v3/contents/generations/tasks");
if (parsed == null) {
throw new Exception("listVideoGenerationTasks errorinvalid base url");
}
HttpUrl url = parsed.newBuilder()
.addQueryParameter("page_num", String.valueOf(pn))
.addQueryParameter("page_size", String.valueOf(ps))
.build();
Request request = new Request.Builder()
.url(url)
.header("Content-Type", "application/json")
.header("Authorization", "Bearer " + arkApiKey)
.get()
.build();
Response response = OkHttpUtils.newCall(request).execute();
if (response.body() == null) {
throw new Exception("listVideoGenerationTasks response null");
}
String body = response.body().string();
if (!response.isSuccessful()) {
throw new Exception("listVideoGenerationTasks error" + body);
}
return body;
}
} }

View File

@ -21,10 +21,18 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="source" column="source" /> <result property="source" column="source" />
<result property="text" column="text" /> <result property="text" column="text" />
<result property="isTop" column="is_top" /> <result property="isTop" column="is_top" />
<result property="img1" column="img1" />
<result property="img2" column="img2" />
<result property="mode" column="mode" />
<result property="duration" column="duration" />
<result property="resolution" column="resolution" />
<result property="ratio" column="ratio" />
<result property="model" column="model" />
<result property="videoParams" column="video_params" />
</resultMap> </resultMap>
<sql id="selectAiOrderVo"> <sql id="selectAiOrderVo">
select ao.id, ao.del_flag, ao.create_by, ao.create_time, ao.update_by, ao.update_time, ao.remark, ao.order_num, ao.user_id, ao.type, ao.amount, ao.result, ao.status, ao.source, ao.text, ao.is_top, au.user_id uuid from ai_order ao select ao.id, ao.del_flag, ao.create_by, ao.create_time, ao.update_by, ao.update_time, ao.remark, ao.order_num, ao.user_id, ao.type, ao.amount, ao.result, ao.status, ao.source, ao.text, ao.is_top, ao.img1, ao.img2, ao.mode, ao.duration, ao.resolution, ao.ratio, ao.model, ao.video_params, au.user_id uuid from ai_order ao
left join ai_user au on au.id = ao.user_id left join ai_user au on au.id = ao.user_id
</sql> </sql>
@ -61,6 +69,21 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
where result = #{result} where result = #{result}
</select> </select>
<select id="getAiOrderByPortalVideoTask" resultMap="AiOrderResult">
<include refid="selectAiOrderVo"/>
where ao.del_flag = '0'
and ao.type = '21'
and (
ao.result = #{taskId}
or (
ao.video_params is not null and ao.video_params != ''
and JSON_VALID(ao.video_params)
and JSON_UNQUOTE(JSON_EXTRACT(ao.video_params, '$.volcTaskId')) = #{taskId}
)
)
limit 1
</select>
<select id="getSumAmountByUserId" resultType="java.math.BigDecimal"> <select id="getSumAmountByUserId" resultType="java.math.BigDecimal">
SELECT COALESCE(sum(amount), 0) from ai_order where user_id = #{userId} SELECT COALESCE(sum(amount), 0) from ai_order where user_id = #{userId}
</select> </select>
@ -118,7 +141,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="amount != null">amount = #{amount},</if> <if test="amount != null">amount = #{amount},</if>
<if test="result != null">result = #{result},</if> <if test="result != null">result = #{result},</if>
<if test="status != null">status = #{status},</if> <if test="status != null">status = #{status},</if>
<if test="source != null">status = #{source},</if> <if test="source != null">source = #{source},</if>
<if test="text != null">text = #{text},</if> <if test="text != null">text = #{text},</if>
<if test="isTop != null">is_top = #{isTop},</if> <if test="isTop != null">is_top = #{isTop},</if>
</trim> </trim>

View File

@ -33,15 +33,18 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="source" column="source" /> <result property="source" column="source" />
<result property="ip" column="ip" /> <result property="ip" column="ip" />
<result property="country" column="country" /> <result property="country" column="country" />
<result property="deptId" column="dept_id" />
<result property="deptName" column="dept_name" />
</resultMap> </resultMap>
<sql id="selectAiUserVo"> <sql id="selectAiUserVo">
select id, del_flag, create_by, create_time, update_by, update_time, remark, username, nickname, gender, avatar, phone, password, openid, status, email, birthday, invitation_code, payment_url, login_time, balance, superior_id, user_id, source, ip, country from ai_user select id, del_flag, create_by, create_time, update_by, update_time, remark, username, nickname, gender, avatar, phone, password, openid, status, email, birthday, invitation_code, payment_url, login_time, balance, superior_id, user_id, source, ip, country, dept_id from ai_user
</sql> </sql>
<select id="selectAiUserList" parameterType="AiUser" resultMap="AiUserResult"> <select id="selectAiUserList" parameterType="AiUser" resultMap="AiUserResult">
select u.id, u.del_flag, u.create_by, u.create_time, u.update_by, u.update_time, u.remark, u.username, u.nickname, u.gender, u.avatar, u.phone, u.password, u.openid, u.status, u.email, u.birthday, u.invitation_code, u.payment_url, u.login_time, u.balance, u.superior_id, u.user_id, u.source, u.ip, u.country, au.user_id superiorUuid, au.username superiorName from ai_user u select u.id, u.del_flag, u.create_by, u.create_time, u.update_by, u.update_time, u.remark, u.username, u.nickname, u.gender, u.avatar, u.phone, u.password, u.openid, u.status, u.email, u.birthday, u.invitation_code, u.payment_url, u.login_time, u.balance, u.superior_id, u.user_id, u.source, u.ip, u.country, u.dept_id, d.dept_name, au.user_id superiorUuid, au.username superiorName from ai_user u
left join ai_user au on au.id = u.superior_id left join ai_user au on au.id = u.superior_id
left join sys_dept d on d.dept_id = u.dept_id and d.del_flag = '0'
<where> <where>
<if test="nickname != null and nickname != ''"> and u.nickname like concat('%', #{nickname}, '%')</if> <if test="nickname != null and nickname != ''"> and u.nickname like concat('%', #{nickname}, '%')</if>
<if test="username != null and username != ''"> and u.username like concat('%', #{username}, '%')</if> <if test="username != null and username != ''"> and u.username like concat('%', #{username}, '%')</if>
@ -63,19 +66,26 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="superiorId != null "> and u.superior_id = #{superiorId}</if> <if test="superiorId != null "> and u.superior_id = #{superiorId}</if>
<if test="id != null "> and u.id = #{id}</if> <if test="id != null "> and u.id = #{id}</if>
<if test="source != null "> and u.source = #{source}</if> <if test="source != null "> and u.source = #{source}</if>
<if test="deptId != null "> and u.dept_id = #{deptId}</if>
</where> </where>
order by u.id desc order by u.id desc
</select> </select>
<select id="selectAiUserById" parameterType="Long" resultMap="AiUserResult"> <select id="selectAiUserById" parameterType="Long" resultMap="AiUserResult">
<include refid="selectAiUserVo"/> select u.id, u.del_flag, u.create_by, u.create_time, u.update_by, u.update_time, u.remark, u.username, u.nickname, u.gender, u.avatar, u.phone, u.password, u.openid, u.status, u.email, u.birthday, u.invitation_code, u.payment_url, u.login_time, u.balance, u.superior_id, u.user_id, u.source, u.ip, u.country, u.dept_id, d.dept_name
where id = #{id} from ai_user u
left join sys_dept d on d.dept_id = u.dept_id and d.del_flag = '0'
where u.id = #{id}
</select> </select>
<select id="getUserInfo" parameterType="Long" resultMap="AiUserResult"> <select id="getUserInfo" parameterType="Long" resultMap="AiUserResult">
select del_flag, create_by, create_time, update_by, update_time, remark, username, nickname, gender, avatar, phone, password, openid, status, email, birthday, invitation_code, payment_url, login_time, balance, superior_id, user_id, source from ai_user select del_flag, create_by, create_time, update_by, update_time, remark, username, nickname, gender, avatar, phone, password, openid, status, email, birthday, invitation_code, payment_url, login_time, balance, superior_id, user_id, source, ip, country, dept_id from ai_user
where id = #{id} where id = #{id}
</select> </select>
<select id="countAiUserByDeptId" resultType="int">
select count(1) from ai_user where del_flag = '0' and dept_id = #{deptId}
</select>
<select id="selectPasswordById" resultType="java.lang.String"> <select id="selectPasswordById" resultType="java.lang.String">
select password from ai_user where id = #{id} select password from ai_user where id = #{id}
</select> </select>
@ -108,6 +118,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="source != null">source,</if> <if test="source != null">source,</if>
<if test="ip != null">ip,</if> <if test="ip != null">ip,</if>
<if test="country != null">country,</if> <if test="country != null">country,</if>
<if test="deptId != null">dept_id,</if>
</trim> </trim>
<trim prefix="values (" suffix=")" suffixOverrides=","> <trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="delFlag != null and delFlag != ''">#{delFlag},</if> <if test="delFlag != null and delFlag != ''">#{delFlag},</if>
@ -134,6 +145,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="userId != null">#{userId},</if> <if test="userId != null">#{userId},</if>
<if test="source != null">#{source},</if> <if test="source != null">#{source},</if>
<if test="country != null">#{country},</if> <if test="country != null">#{country},</if>
<if test="deptId != null">#{deptId},</if>
</trim> </trim>
</insert> </insert>
@ -163,8 +175,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="superiorId != null">superior_id = #{superiorId},</if> <if test="superiorId != null">superior_id = #{superiorId},</if>
<if test="userId != null">user_id = #{userId},</if> <if test="userId != null">user_id = #{userId},</if>
<if test="source != null">source = #{source},</if> <if test="source != null">source = #{source},</if>
<if test="ip != null">source = #{ip},</if> <if test="ip != null">ip = #{ip},</if>
<if test="country != null">country = #{country},</if> <if test="country != null">country = #{country},</if>
<if test="deptId != null">dept_id = #{deptId},</if>
</trim> </trim>
where id = #{id} where id = #{id}
</update> </update>

View File

@ -13,6 +13,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="leader" column="leader" /> <result property="leader" column="leader" />
<result property="phone" column="phone" /> <result property="phone" column="phone" />
<result property="email" column="email" /> <result property="email" column="email" />
<result property="byteApiKey" column="byte_api_key" />
<result property="status" column="status" /> <result property="status" column="status" />
<result property="delFlag" column="del_flag" /> <result property="delFlag" column="del_flag" />
<result property="parentName" column="parent_name" /> <result property="parentName" column="parent_name" />
@ -23,7 +24,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</resultMap> </resultMap>
<sql id="selectDeptVo"> <sql id="selectDeptVo">
select d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.phone, d.email, d.status, d.del_flag, d.create_by, d.create_time select d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.phone, d.email, d.byte_api_key, d.status, d.del_flag, d.create_by, d.create_time
from sys_dept d from sys_dept d
</sql> </sql>
@ -59,7 +60,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</select> </select>
<select id="selectDeptById" parameterType="Long" resultMap="SysDeptResult"> <select id="selectDeptById" parameterType="Long" resultMap="SysDeptResult">
select d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.phone, d.email, d.status, select d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.phone, d.email, d.byte_api_key, d.status,
(select dept_name from sys_dept where dept_id = d.parent_id) parent_name (select dept_name from sys_dept where dept_id = d.parent_id) parent_name
from sys_dept d from sys_dept d
where d.dept_id = #{deptId} where d.dept_id = #{deptId}
@ -101,6 +102,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="leader != null and leader != ''">leader,</if> <if test="leader != null and leader != ''">leader,</if>
<if test="phone != null and phone != ''">phone,</if> <if test="phone != null and phone != ''">phone,</if>
<if test="email != null and email != ''">email,</if> <if test="email != null and email != ''">email,</if>
<if test="byteApiKey != null">byte_api_key,</if>
<if test="status != null">status,</if> <if test="status != null">status,</if>
<if test="createBy != null and createBy != ''">create_by,</if> <if test="createBy != null and createBy != ''">create_by,</if>
create_time create_time
@ -113,6 +115,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="leader != null and leader != ''">#{leader},</if> <if test="leader != null and leader != ''">#{leader},</if>
<if test="phone != null and phone != ''">#{phone},</if> <if test="phone != null and phone != ''">#{phone},</if>
<if test="email != null and email != ''">#{email},</if> <if test="email != null and email != ''">#{email},</if>
<if test="byteApiKey != null">#{byteApiKey},</if>
<if test="status != null">#{status},</if> <if test="status != null">#{status},</if>
<if test="createBy != null and createBy != ''">#{createBy},</if> <if test="createBy != null and createBy != ''">#{createBy},</if>
sysdate() sysdate()
@ -129,6 +132,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="leader != null">leader = #{leader},</if> <if test="leader != null">leader = #{leader},</if>
<if test="phone != null">phone = #{phone},</if> <if test="phone != null">phone = #{phone},</if>
<if test="email != null">email = #{email},</if> <if test="email != null">email = #{email},</if>
<if test="byteApiKey != null">byte_api_key = #{byteApiKey},</if>
<if test="status != null and status != ''">status = #{status},</if> <if test="status != null and status != ''">status = #{status},</if>
<if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if> <if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>
update_time = sysdate() update_time = sysdate()

View File

@ -1500,6 +1500,8 @@ CREATE TABLE `ai_order` (
`duration` int NULL DEFAULT 5 COMMENT '视频时长(秒)', `duration` int NULL DEFAULT 5 COMMENT '视频时长(秒)',
`resolution` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '720p' COMMENT '分辨率', `resolution` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '720p' COMMENT '分辨率',
`ratio` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '9:16' COMMENT '宽高比', `ratio` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '9:16' COMMENT '宽高比',
`model` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '火山模型 endpoint',
`video_params` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '视频生成提交参数JSON',
PRIMARY KEY (`id`) USING BTREE, PRIMARY KEY (`id`) USING BTREE,
KEY `idx_order_num` (`order_num`) USING BTREE, KEY `idx_order_num` (`order_num`) USING BTREE,
KEY `idx_user_id` (`user_id`) USING BTREE KEY `idx_user_id` (`user_id`) USING BTREE
@ -3539,6 +3541,7 @@ CREATE TABLE `ai_user` (
`source` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '来源', `source` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '来源',
`ip` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用户IP', `ip` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用户IP',
`country` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '隶属国家', `country` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '隶属国家',
`dept_id` bigint NULL DEFAULT NULL COMMENT '归属部门sys_dept.dept_id',
PRIMARY KEY (`id`) USING BTREE, PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `uuid`(`user_id` ASC) USING BTREE, UNIQUE INDEX `uuid`(`user_id` ASC) USING BTREE,
UNIQUE INDEX `invitation_code`(`invitation_code` ASC) USING BTREE, UNIQUE INDEX `invitation_code`(`invitation_code` ASC) USING BTREE,
@ -3549,35 +3552,37 @@ CREATE TABLE `ai_user` (
-- ---------------------------- -- ----------------------------
-- Records of ai_user -- Records of ai_user
-- ---------------------------- -- ----------------------------
INSERT INTO `ai_user` VALUES (14, '0', '', '2025-11-28 11:42:33', '', '2026-01-06 16:04:21', NULL, 'ww123', NULL, 2, '', '', '$2a$10$bxNPP2cfo9OlJxiOQJJDiu4QOrQet8enUOCiu3QF6qLHaOSLA6G1.', NULL, 0, 'xpchb40121@outlook.com', NULL, 'RM3XZ8z3', NULL, '2026-01-06 16:04:21', 235.00, NULL, 'L8AJXFPT', 'XM001', '2605:52c0:1:446:a425:64ff:fe47:36c6', '美国'); INSERT INTO `ai_user` VALUES (14, '0', '', '2025-11-28 11:42:33', '', '2026-01-06 16:04:21', NULL, 'ww123', NULL, 2, '', '', '$2a$10$bxNPP2cfo9OlJxiOQJJDiu4QOrQet8enUOCiu3QF6qLHaOSLA6G1.', NULL, 0, 'xpchb40121@outlook.com', NULL, 'RM3XZ8z3', NULL, '2026-01-06 16:04:21', 235.00, NULL, 'L8AJXFPT', 'XM001', '2605:52c0:1:446:a425:64ff:fe47:36c6', '美国', NULL);
INSERT INTO `ai_user` VALUES (15, '0', '', '2025-12-07 14:52:38', '', '2025-12-08 17:20:37', NULL, 'u30', NULL, 2, '', '', '$2a$10$tXkZP66AWniOcCbhk2LJpOFOSzHEIMLDbGsow4B7maYswco5HShg.', NULL, 0, 'u30@163.com', NULL, 'wHSf4N2v', NULL, '2025-12-08 17:20:37', 10.00, NULL, 'SNLMZXPH', 'XM001', '208.86.32.27', '美国'); INSERT INTO `ai_user` VALUES (15, '0', '', '2025-12-07 14:52:38', '', '2025-12-08 17:20:37', NULL, 'u30', NULL, 2, '', '', '$2a$10$tXkZP66AWniOcCbhk2LJpOFOSzHEIMLDbGsow4B7maYswco5HShg.', NULL, 0, 'u30@163.com', NULL, 'wHSf4N2v', NULL, '2025-12-08 17:20:37', 10.00, NULL, 'SNLMZXPH', 'XM001', '208.86.32.27', '美国', NULL);
INSERT INTO `ai_user` VALUES (16, '0', '', '2025-12-07 17:15:46', '', '2026-01-08 09:08:03', NULL, 'test001', NULL, 2, '', '', '$2a$10$M4ZD5kRehFycoTmgrA1b4.XNnwsvULaQm9ySdSxttRzPVn7ngbE6y', NULL, 0, 'fgerghbrthbrt@gmail.com', NULL, 'XrtN5DDW', NULL, '2026-01-08 09:08:03', 99921.00, NULL, '2LZ9RAC2', '', '15.204.58.244', '美国'); INSERT INTO `ai_user` VALUES (16, '0', '', '2025-12-07 17:15:46', '', '2026-01-08 09:08:03', NULL, 'test001', NULL, 2, '', '', '$2a$10$M4ZD5kRehFycoTmgrA1b4.XNnwsvULaQm9ySdSxttRzPVn7ngbE6y', NULL, 0, 'fgerghbrthbrt@gmail.com', NULL, 'XrtN5DDW', NULL, '2026-01-08 09:08:03', 99921.00, NULL, '2LZ9RAC2', '', '15.204.58.244', '美国', NULL);
INSERT INTO `ai_user` VALUES (17, '0', '', '2025-12-07 17:28:57', '', '2025-12-07 09:28:57', NULL, 'zz3534217@gmail.com', NULL, 2, '', '', '$2a$10$sxNmfnayqUroy66CgCATf.VkmxsECKv1jTUgFUMN.CQY.3yFBWGO.', NULL, 0, 'zz3534217@gmail.com', NULL, 'qnUwmXYS', NULL, '2025-12-07 21:18:48', 0.00, NULL, '82FR6YTZ', 'XM001', NULL, NULL); INSERT INTO `ai_user` VALUES (17, '0', '', '2025-12-07 17:28:57', '', '2025-12-07 09:28:57', NULL, 'zz3534217@gmail.com', NULL, 2, '', '', '$2a$10$sxNmfnayqUroy66CgCATf.VkmxsECKv1jTUgFUMN.CQY.3yFBWGO.', NULL, 0, 'zz3534217@gmail.com', NULL, 'qnUwmXYS', NULL, '2025-12-07 21:18:48', 0.00, NULL, '82FR6YTZ', 'XM001', NULL, NULL, NULL);
INSERT INTO `ai_user` VALUES (18, '0', '', '2025-12-08 12:53:23', '', '2025-12-08 17:00:57', NULL, '3545486624@qq.com', NULL, 2, '', '', '$2a$10$9siQceU./ZfmW.iDwVf9sehBJWsxzyP10fJvkzStAbyzw4yQEHAUa', NULL, 0, '3545486624@qq.com', NULL, 'ujfTuFNA', NULL, '2025-12-08 17:00:56', 0.00, NULL, 'OEEO8YJQ', 'XM001', '119.246.86.101', '香港'); INSERT INTO `ai_user` VALUES (18, '0', '', '2025-12-08 12:53:23', '', '2025-12-08 17:00:57', NULL, '3545486624@qq.com', NULL, 2, '', '', '$2a$10$9siQceU./ZfmW.iDwVf9sehBJWsxzyP10fJvkzStAbyzw4yQEHAUa', NULL, 0, '3545486624@qq.com', NULL, 'ujfTuFNA', NULL, '2025-12-08 17:00:56', 0.00, NULL, 'OEEO8YJQ', 'XM001', '119.246.86.101', '香港', NULL);
INSERT INTO `ai_user` VALUES (19, '0', '', '2025-12-08 15:47:59', '', '2025-12-08 15:48:14', NULL, 'walb0501', NULL, 2, '', '', '$2a$10$KnHIeNIOtva0saZVasbfBeJhvCKpU/cjZXEwBJ655jrJcBnCR1s/q', NULL, 0, 'pereadesen2@gmail.com', NULL, 'DqmbQS8q', NULL, '2025-12-08 15:48:14', 8.00, NULL, '9Q889UMZ', 'XM001', '188.253.121.195', '新加坡'); INSERT INTO `ai_user` VALUES (19, '0', '', '2025-12-08 15:47:59', '', '2025-12-08 15:48:14', NULL, 'walb0501', NULL, 2, '', '', '$2a$10$KnHIeNIOtva0saZVasbfBeJhvCKpU/cjZXEwBJ655jrJcBnCR1s/q', NULL, 0, 'pereadesen2@gmail.com', NULL, 'DqmbQS8q', NULL, '2025-12-08 15:48:14', 8.00, NULL, '9Q889UMZ', 'XM001', '188.253.121.195', '新加坡', NULL);
INSERT INTO `ai_user` VALUES (20, '0', '', '2025-12-08 15:50:03', '', '2025-12-08 15:50:23', NULL, 'xu89026719@gmail.com', NULL, 2, '', '', '$2a$10$xdGHiEVaGC7gyXldojpiUO0GOgyu5Pcgtw/WRTuf.TA1e.NbB8Ogu', NULL, 0, 'xu89026719@gmail.com', NULL, 'XnQAfPvA', NULL, '2025-12-08 15:50:23', 0.00, NULL, '209HPBTF', 'XM001', '38.207.136.194', '日本'); INSERT INTO `ai_user` VALUES (20, '0', '', '2025-12-08 15:50:03', '', '2025-12-08 15:50:23', NULL, 'xu89026719@gmail.com', NULL, 2, '', '', '$2a$10$xdGHiEVaGC7gyXldojpiUO0GOgyu5Pcgtw/WRTuf.TA1e.NbB8Ogu', NULL, 0, 'xu89026719@gmail.com', NULL, 'XnQAfPvA', NULL, '2025-12-08 15:50:23', 0.00, NULL, '209HPBTF', 'XM001', '38.207.136.194', '日本', NULL);
INSERT INTO `ai_user` VALUES (21, '0', '', '2025-12-08 17:20:31', '', '2025-12-08 17:22:26', NULL, '1686228', NULL, 2, '', '', '$2a$10$MpUYTeWBI6gVTqjtJBz.3.sMOz6ul.eqLQyrvY3VL2WRbFeK666fW', NULL, 0, '1686228@gmail.com', NULL, 'RyZlK7YG', NULL, '2025-12-08 17:22:26', 10.00, NULL, '9CUIDFW4', 'XM001', '208.86.32.27', '美国'); INSERT INTO `ai_user` VALUES (21, '0', '', '2025-12-08 17:20:31', '', '2025-12-08 17:22:26', NULL, '1686228', NULL, 2, '', '', '$2a$10$MpUYTeWBI6gVTqjtJBz.3.sMOz6ul.eqLQyrvY3VL2WRbFeK666fW', NULL, 0, '1686228@gmail.com', NULL, 'RyZlK7YG', NULL, '2025-12-08 17:22:26', 10.00, NULL, '9CUIDFW4', 'XM001', '208.86.32.27', '美国', NULL);
INSERT INTO `ai_user` VALUES (22, '0', '', '2025-12-08 19:45:16', '', '2025-12-09 03:12:37', NULL, 'a424569211@gmail.com', NULL, 2, '', '', '$2a$10$3TEa4ufju1sMPJdw8K0Ik.ic10m6Ms4LQFxYK2h27/pbI2qR5nJDK', NULL, 0, 'a424569211@gmail.com', NULL, '4JLEc4vd', NULL, '2025-12-09 03:12:37', 0.00, NULL, '0N5NEU38', 'XM001', '205.185.125.114', '美国'); INSERT INTO `ai_user` VALUES (22, '0', '', '2025-12-08 19:45:16', '', '2025-12-09 03:12:37', NULL, 'a424569211@gmail.com', NULL, 2, '', '', '$2a$10$3TEa4ufju1sMPJdw8K0Ik.ic10m6Ms4LQFxYK2h27/pbI2qR5nJDK', NULL, 0, 'a424569211@gmail.com', NULL, '4JLEc4vd', NULL, '2025-12-09 03:12:37', 0.00, NULL, '0N5NEU38', 'XM001', '205.185.125.114', '美国', NULL);
INSERT INTO `ai_user` VALUES (23, '0', '', '2025-12-09 10:33:05', '', '2025-12-09 10:33:21', NULL, 'cc123', NULL, 2, 'https://images.iqyjsnwv.com/2025/12/09/37b754c5_706d42be-ad9a-4f11-a3ec-c0742e97ed64.png', '', '$2a$10$V.SDRP4RgM/qfAmNMSqIdOOM259j064oJCvAbDkhrSZLB99L9nhaK', NULL, 0, 'cherrylux098@gmail.com', NULL, 'rlmhwbhF', NULL, '2025-12-09 10:33:21', 4.00, NULL, 'NU8BE6J2', 'XM001', '2605:52c0:3:1a3:c05b:4bff:fe2c:115a', '美国'); INSERT INTO `ai_user` VALUES (23, '0', '', '2025-12-09 10:33:05', '', '2025-12-09 10:33:21', NULL, 'cc123', NULL, 2, 'https://images.iqyjsnwv.com/2025/12/09/37b754c5_706d42be-ad9a-4f11-a3ec-c0742e97ed64.png', '', '$2a$10$V.SDRP4RgM/qfAmNMSqIdOOM259j064oJCvAbDkhrSZLB99L9nhaK', NULL, 0, 'cherrylux098@gmail.com', NULL, 'rlmhwbhF', NULL, '2025-12-09 10:33:21', 4.00, NULL, 'NU8BE6J2', 'XM001', '2605:52c0:3:1a3:c05b:4bff:fe2c:115a', '美国', NULL);
INSERT INTO `ai_user` VALUES (25, '0', '', '2025-12-09 13:46:13', '', '2025-12-09 14:31:51', NULL, 'test1', NULL, 2, '', '', '$2a$10$7v6PPfozY7PHR.ep.GKobePag1aq0ZuS9j.R6lWcKloy9j1R6HgoS', NULL, 0, '123@gmail.com', NULL, 'VBb72Ym3', NULL, '2025-12-09 14:31:50', 8.00, NULL, 'UQ9WZN3V', 'XM001', '2407:cdc0:b00a::19', '香港'); INSERT INTO `ai_user` VALUES (25, '0', '', '2025-12-09 13:46:13', '', '2025-12-09 14:31:51', NULL, 'test1', NULL, 2, '', '', '$2a$10$7v6PPfozY7PHR.ep.GKobePag1aq0ZuS9j.R6lWcKloy9j1R6HgoS', NULL, 0, '123@gmail.com', NULL, 'VBb72Ym3', NULL, '2025-12-09 14:31:50', 8.00, NULL, 'UQ9WZN3V', 'XM001', '2407:cdc0:b00a::19', '香港', NULL);
INSERT INTO `ai_user` VALUES (26, '0', '', '2025-12-09 14:13:17', '', '2025-12-09 14:53:48', NULL, 'test2', NULL, 2, '', '', '$2a$10$OirrwiDFruMJQLLnNufEv.BiQzyL.KxCz1x.XVWt5R5e.ggq5m/RS', NULL, 0, '1@gmail.com', NULL, '3WFmGuER', NULL, '2025-12-09 14:53:48', 10.00, NULL, '0NEK09R6', 'XM001', '2407:cdc0:b00a::19', '香港'); INSERT INTO `ai_user` VALUES (26, '0', '', '2025-12-09 14:13:17', '', '2025-12-09 14:53:48', NULL, 'test2', NULL, 2, '', '', '$2a$10$OirrwiDFruMJQLLnNufEv.BiQzyL.KxCz1x.XVWt5R5e.ggq5m/RS', NULL, 0, '1@gmail.com', NULL, '3WFmGuER', NULL, '2025-12-09 14:53:48', 10.00, NULL, '0NEK09R6', 'XM001', '2407:cdc0:b00a::19', '香港', NULL);
INSERT INTO `ai_user` VALUES (27, '0', '', '2025-12-09 14:57:14', '', '2025-12-09 15:01:08', NULL, 'test3', NULL, 2, '', '', '$2a$10$aCcA6Mq/.xOfs6FCJwPot.ttBFv7YjULPQsF3axMz3Gm98MzMafrO', NULL, 0, '2@gmail.com', NULL, 'pqU7mW5R', NULL, '2025-12-09 15:01:08', 10000.00, NULL, '4R80E3NI', 'XM001', '2407:cdc0:b00a::19', '香港'); INSERT INTO `ai_user` VALUES (27, '0', '', '2025-12-09 14:57:14', '', '2025-12-09 15:01:08', NULL, 'test3', NULL, 2, '', '', '$2a$10$aCcA6Mq/.xOfs6FCJwPot.ttBFv7YjULPQsF3axMz3Gm98MzMafrO', NULL, 0, '2@gmail.com', NULL, 'pqU7mW5R', NULL, '2025-12-09 15:01:08', 10000.00, NULL, '4R80E3NI', 'XM001', '2407:cdc0:b00a::19', '香港', NULL);
INSERT INTO `ai_user` VALUES (29, '0', '', '2025-12-11 10:48:59', '', '2025-12-11 10:49:08', NULL, 'test4', NULL, 2, '', '', '$2a$10$he3GMBisX7UeEHFRQYVxU.vcavkDxWWNyCSuz2QvfPKBAEZd17Xuu', NULL, 0, '3@gmail.com', NULL, 'FWzJWjjQ', NULL, '2025-12-11 10:49:08', 0.00, NULL, 'KLSC4HK0', 'ALL', '2407:cdc0:b00a::19', '香港'); INSERT INTO `ai_user` VALUES (29, '0', '', '2025-12-11 10:48:59', '', '2025-12-11 10:49:08', NULL, 'test4', NULL, 2, '', '', '$2a$10$he3GMBisX7UeEHFRQYVxU.vcavkDxWWNyCSuz2QvfPKBAEZd17Xuu', NULL, 0, '3@gmail.com', NULL, 'FWzJWjjQ', NULL, '2025-12-11 10:49:08', 0.00, NULL, 'KLSC4HK0', 'ALL', '2407:cdc0:b00a::19', '香港', NULL);
INSERT INTO `ai_user` VALUES (30, '0', '', '2025-12-11 10:50:31', '', '2025-12-11 11:00:47', NULL, 'test5', NULL, 2, '', '', '$2a$10$QVUfOv2FbwhRwj35ETn0we.k76tfHNqxXZPKy0vvzxfz1jgh2cB7m', NULL, 0, '4@gmail.com', NULL, 'Rdp7l3db', NULL, '2025-12-11 11:00:47', 28.22, NULL, '1S8WYOXT', 'ALL', '2407:cdc0:b00a::19', '香港'); INSERT INTO `ai_user` VALUES (30, '0', '', '2025-12-11 10:50:31', '', '2025-12-11 11:00:47', NULL, 'test5', NULL, 2, '', '', '$2a$10$QVUfOv2FbwhRwj35ETn0we.k76tfHNqxXZPKy0vvzxfz1jgh2cB7m', NULL, 0, '4@gmail.com', NULL, 'Rdp7l3db', NULL, '2025-12-11 11:00:47', 28.22, NULL, '1S8WYOXT', 'ALL', '2407:cdc0:b00a::19', '香港', NULL);
INSERT INTO `ai_user` VALUES (31, '0', '', '2025-12-14 01:35:44', '', '2025-12-13 17:35:44', NULL, 'whsksmhxud', NULL, 2, '', '', '$2a$10$sJ1pA9uBfgzv8O5X5Ui5G.7uVKRoZDqDqQ9BG848y7njgFtlgzWpq', NULL, 0, 'w809277959@outlook.com', NULL, 'bZEVdu4b', NULL, NULL, 0.00, NULL, '7I7TJC30', 'XM001', '103.82.93.21', '印尼'); INSERT INTO `ai_user` VALUES (31, '0', '', '2025-12-14 01:35:44', '', '2025-12-13 17:35:44', NULL, 'whsksmhxud', NULL, 2, '', '', '$2a$10$sJ1pA9uBfgzv8O5X5Ui5G.7uVKRoZDqDqQ9BG848y7njgFtlgzWpq', NULL, 0, 'w809277959@outlook.com', NULL, 'bZEVdu4b', NULL, NULL, 0.00, NULL, '7I7TJC30', 'XM001', '103.82.93.21', '印尼', NULL);
INSERT INTO `ai_user` VALUES (32, '0', '', '2025-12-14 01:58:22', '', '2025-12-14 01:58:47', NULL, 'devin', NULL, 2, '', '', '$2a$10$NUNiFbS6WEXznA0LzlW10eH5FjX437NxO05VSnMFII4FIsPQOuoxe', NULL, 0, 'devinhe46@gmail.com', NULL, 'BZNhTE5M', NULL, '2025-12-14 01:58:47', 0.00, NULL, 'BN7FJCGI', 'XM001', '134.122.184.12', '日本'); INSERT INTO `ai_user` VALUES (32, '0', '', '2025-12-14 01:58:22', '', '2025-12-14 01:58:47', NULL, 'devin', NULL, 2, '', '', '$2a$10$NUNiFbS6WEXznA0LzlW10eH5FjX437NxO05VSnMFII4FIsPQOuoxe', NULL, 0, 'devinhe46@gmail.com', NULL, 'BZNhTE5M', NULL, '2025-12-14 01:58:47', 0.00, NULL, 'BN7FJCGI', 'XM001', '134.122.184.12', '日本', NULL);
INSERT INTO `ai_user` VALUES (33, '0', '', '2025-12-14 10:22:49', '', '2025-12-14 10:23:08', NULL, 'djwnx1123', NULL, 2, '', '', '$2a$10$z5dYmkZzGdi9G2nVSPZqJutN2Z/8FN0.cPRilsZdjzgVZKc2QCydi', NULL, 0, '2451855921@qq.com', NULL, 'nc3yv7WQ', NULL, '2025-12-14 10:23:08', 0.00, NULL, '4HF1953W', 'XM001', '103.147.45.37', '香港'); INSERT INTO `ai_user` VALUES (33, '0', '', '2025-12-14 10:22:49', '', '2025-12-14 10:23:08', NULL, 'djwnx1123', NULL, 2, '', '', '$2a$10$z5dYmkZzGdi9G2nVSPZqJutN2Z/8FN0.cPRilsZdjzgVZKc2QCydi', NULL, 0, '2451855921@qq.com', NULL, 'nc3yv7WQ', NULL, '2025-12-14 10:23:08', 0.00, NULL, '4HF1953W', 'XM001', '103.147.45.37', '香港', NULL);
INSERT INTO `ai_user` VALUES (34, '0', '', '2025-12-14 14:52:58', '', '2025-12-14 14:54:08', NULL, 'djwnx', NULL, 2, '', '', '$2a$10$YwtgWJOnElfAn4vuvYRprO5zXrTBZx8fvx/lVIyopVdph7RkeSisS', NULL, 0, 'tianyangyu1123@gmail.com', NULL, 'pFpHVX2y', NULL, '2025-12-14 14:54:08', 0.00, NULL, 'BH9DLPCJ', 'XM001', '43.228.227.211', '香港'); INSERT INTO `ai_user` VALUES (34, '0', '', '2025-12-14 14:52:58', '', '2025-12-14 14:54:08', NULL, 'djwnx', NULL, 2, '', '', '$2a$10$YwtgWJOnElfAn4vuvYRprO5zXrTBZx8fvx/lVIyopVdph7RkeSisS', NULL, 0, 'tianyangyu1123@gmail.com', NULL, 'pFpHVX2y', NULL, '2025-12-14 14:54:08', 0.00, NULL, 'BH9DLPCJ', 'XM001', '43.228.227.211', '香港', NULL);
INSERT INTO `ai_user` VALUES (35, '0', '', '2025-12-15 18:05:01', '', '2025-12-24 15:08:10', NULL, 'test6', NULL, 2, '', '', '$2a$10$AOJg.25lz16afHa3OfPMhuxu8oorFGeL4MqMgcxpRKjd4iY0LsmAG', NULL, 0, '5@gmail.com', NULL, 'heNUTHUX', NULL, '2025-12-24 15:08:09', 323.00, 30, 'PJCZNE1M', 'ALL', '2602:fbf1:b001::36', '美国'); INSERT INTO `ai_user` VALUES (35, '0', '', '2025-12-15 18:05:01', '', '2025-12-24 15:08:10', NULL, 'test6', NULL, 2, '', '', '$2a$10$AOJg.25lz16afHa3OfPMhuxu8oorFGeL4MqMgcxpRKjd4iY0LsmAG', NULL, 0, '5@gmail.com', NULL, 'heNUTHUX', NULL, '2025-12-24 15:08:09', 323.00, 30, 'PJCZNE1M', 'ALL', '2602:fbf1:b001::36', '美国', NULL);
INSERT INTO `ai_user` VALUES (36, '0', '', '2025-12-15 18:07:56', '', '2026-01-08 14:53:02', NULL, 'test7', NULL, 2, '', '', '$2a$10$xXtOsMjz5Zd9dsJvUBz5be.6ZphexWOedfe.TLW9bdDtzFBYESzIG', NULL, 0, '6@gmail.com', NULL, 'RXQLfyjy', NULL, '2026-01-08 14:53:01', 100419.00, 35, '24SRSLFG', 'ALL', '2407:cdc0:d002::195', '新加坡'); INSERT INTO `ai_user` VALUES (36, '0', '', '2025-12-15 18:07:56', '', '2026-01-08 14:53:02', NULL, 'test7', NULL, 2, '', '', '$2a$10$xXtOsMjz5Zd9dsJvUBz5be.6ZphexWOedfe.TLW9bdDtzFBYESzIG', NULL, 0, '6@gmail.com', NULL, 'RXQLfyjy', NULL, '2026-01-08 14:53:01', 100419.00, 35, '24SRSLFG', 'ALL', '2407:cdc0:d002::195', '新加坡', NULL);
INSERT INTO `ai_user` VALUES (37, '0', '', '2025-12-16 14:07:46', '', '2025-12-16 14:08:05', NULL, 'test8', NULL, 2, '', '', '$2a$10$Z967MUQ6I5CCgfVJTV0l2ug2BysZmfRNvpq6c.vBVlVIX7ekM3GJi', NULL, 0, '7@gmail.com', NULL, 'kEZx2eps', NULL, '2025-12-16 14:08:04', 0.00, NULL, 'H4AFA8CH', 'ALL', '37.9.33.202', '美国'); INSERT INTO `ai_user` VALUES (37, '0', '', '2025-12-16 14:07:46', '', '2025-12-16 14:08:05', NULL, 'test8', NULL, 2, '', '', '$2a$10$Z967MUQ6I5CCgfVJTV0l2ug2BysZmfRNvpq6c.vBVlVIX7ekM3GJi', NULL, 0, '7@gmail.com', NULL, 'kEZx2eps', NULL, '2025-12-16 14:08:04', 0.00, NULL, 'H4AFA8CH', 'ALL', '37.9.33.202', '美国', NULL);
INSERT INTO `ai_user` VALUES (38, '0', '', '2025-12-19 22:04:18', '', '2025-12-24 20:57:53', NULL, 'ghypnus', NULL, 2, '', '', '$2a$10$Cr7AQ7D9Jxk6BRE7cYn1su5B4x4aOxkf9JQMwk06Tyt5X1dn8Qr6K', NULL, 0, '1954579286@qq.com', NULL, '3tMwDlMH', NULL, '2025-12-24 20:57:52', 0.00, NULL, 'JPL28UHV', 'XM001', '85.234.69.52', '英国'); INSERT INTO `ai_user` VALUES (38, '0', '', '2025-12-19 22:04:18', '', '2025-12-24 20:57:53', NULL, 'ghypnus', NULL, 2, '', '', '$2a$10$Cr7AQ7D9Jxk6BRE7cYn1su5B4x4aOxkf9JQMwk06Tyt5X1dn8Qr6K', NULL, 0, '1954579286@qq.com', NULL, '3tMwDlMH', NULL, '2025-12-24 20:57:52', 0.00, NULL, 'JPL28UHV', 'XM001', '85.234.69.52', '英国', NULL);
INSERT INTO `ai_user` VALUES (39, '0', '', '2025-12-27 16:48:23', '', '2026-01-06 16:32:09', NULL, 'xiaxiaxia', NULL, 2, '', '', '$2a$10$aci4cfcpANfKt1EPdVY1cORUACqXJHGx49gjD72Cc2p62K5TKT6bG', NULL, 0, 'pianochen606@gmail.com', NULL, 'yWQK4jBC', NULL, '2026-01-06 16:32:09', 9829.00, NULL, 'K0G1NBAI', 'XM001', '216.167.64.103', '美国'); INSERT INTO `ai_user` VALUES (39, '0', '', '2025-12-27 16:48:23', '', '2026-01-06 16:32:09', NULL, 'xiaxiaxia', NULL, 2, '', '', '$2a$10$aci4cfcpANfKt1EPdVY1cORUACqXJHGx49gjD72Cc2p62K5TKT6bG', NULL, 0, 'pianochen606@gmail.com', NULL, 'yWQK4jBC', NULL, '2026-01-06 16:32:09', 9829.00, NULL, 'K0G1NBAI', 'XM001', '216.167.64.103', '美国', NULL);
INSERT INTO `ai_user` VALUES (40, '0', '', '2025-12-30 11:28:25', '', '2025-12-30 11:28:35', NULL, 'test9', NULL, 2, '', '', '$2a$10$RrqVCQk2eKBrk4LqVlVLg.MCSmKlIJidSpw/aH3jlA4oGf8AEvbYi', NULL, 0, '8@gmail.com', NULL, 'wSsxXKeH', NULL, '2025-12-30 11:28:35', 336.00, 35, 'Z6UI3X6S', 'ALL', '2602:fbf1:b001::36', '美国'); INSERT INTO `ai_user` VALUES (40, '0', '', '2025-12-30 11:28:25', '', '2025-12-30 11:28:35', NULL, 'test9', NULL, 2, '', '', '$2a$10$RrqVCQk2eKBrk4LqVlVLg.MCSmKlIJidSpw/aH3jlA4oGf8AEvbYi', NULL, 0, '8@gmail.com', NULL, 'wSsxXKeH', NULL, '2025-12-30 11:28:35', 336.00, 35, 'Z6UI3X6S', 'ALL', '2602:fbf1:b001::36', '美国', NULL);
INSERT INTO `ai_user` VALUES (41, '0', '', '2025-12-30 11:58:13', '', '2025-12-30 11:58:20', NULL, 'test10', NULL, 2, '', '', '$2a$10$iyc.quT3QzzzROdjLN1S8.GLE.epyFAo4FvBDOlokDbu4JMODrr3S', NULL, 0, '9@gmail.com', NULL, 'lRbwts88', NULL, '2025-12-30 11:58:20', 110.00, 40, 'LJSSMAQO', 'ALL', '2602:fbf1:b001::36', '美国'); INSERT INTO `ai_user` VALUES (41, '0', '', '2025-12-30 11:58:13', '', '2025-12-30 11:58:20', NULL, 'test10', NULL, 2, '', '', '$2a$10$iyc.quT3QzzzROdjLN1S8.GLE.epyFAo4FvBDOlokDbu4JMODrr3S', NULL, 0, '9@gmail.com', NULL, 'lRbwts88', NULL, '2025-12-30 11:58:20', 110.00, 40, 'LJSSMAQO', 'ALL', '2602:fbf1:b001::36', '美国', NULL);
INSERT INTO `ai_user` VALUES (42, '0', '', '2025-12-30 13:42:02', '', '2025-12-30 13:42:09', NULL, 'test11', NULL, 2, '', '', '$2a$10$ke66b3aOZ67NaUT2WQepyO2EmVYkSEBYLB/NFSRID.S3ejHaU5Og.', NULL, 0, '10@gmail.com', NULL, 'BrEg6XmM', NULL, '2025-12-30 13:42:09', 225.00, NULL, 'IHOF63N5', 'ALL', '2602:fbf1:b001::36', '美国'); INSERT INTO `ai_user` VALUES (42, '0', '', '2025-12-30 13:42:02', '', '2025-12-30 13:42:09', NULL, 'test11', NULL, 2, '', '', '$2a$10$ke66b3aOZ67NaUT2WQepyO2EmVYkSEBYLB/NFSRID.S3ejHaU5Og.', NULL, 0, '10@gmail.com', NULL, 'BrEg6XmM', NULL, '2025-12-30 13:42:09', 225.00, NULL, 'IHOF63N5', 'ALL', '2602:fbf1:b001::36', '美国', NULL);
INSERT INTO `ai_user` VALUES (43, '0', '', '2025-12-31 14:20:06', '', '2025-12-31 14:20:12', NULL, 'a001', NULL, 2, '', '', '$2a$10$Z02VVJ5/LaiTzTp22b2zXOTV8YE/6BMNVrboTj5cuEthXuPpP97Mi', NULL, 0, '11@gmail.com', NULL, 'Xf38CXD6', NULL, '2025-12-31 14:20:12', 1089.00, NULL, 'LXNFP1VS', 'ALL', '2602:fbf1:b001::36', '美国'); INSERT INTO `ai_user` VALUES (43, '0', '', '2025-12-31 14:20:06', '', '2025-12-31 14:20:12', NULL, 'a001', NULL, 2, '', '', '$2a$10$Z02VVJ5/LaiTzTp22b2zXOTV8YE/6BMNVrboTj5cuEthXuPpP97Mi', NULL, 0, '11@gmail.com', NULL, 'Xf38CXD6', NULL, '2025-12-31 14:20:12', 1089.00, NULL, 'LXNFP1VS', 'ALL', '2602:fbf1:b001::36', '美国', NULL);
INSERT INTO `ai_user` VALUES (44, '0', '', '2025-12-31 14:26:20', '', '2025-12-31 14:26:25', NULL, 'a002', NULL, 2, '', '', '$2a$10$4ZnF/zh3q3E07GBpthtL.ufsxQOt2u/eu8YzcFnmPO5dUa1RJ6mkG', NULL, 0, 'c46258724hk@gmail.com', NULL, 'knt2yT2r', NULL, '2025-12-31 14:26:25', 230.00, 43, 'JW07BAHC', 'ALL', '2602:fbf1:b001::36', '美国'); INSERT INTO `ai_user` VALUES (44, '0', '', '2025-12-31 14:26:20', '', '2025-12-31 14:26:25', NULL, 'a002', NULL, 2, '', '', '$2a$10$4ZnF/zh3q3E07GBpthtL.ufsxQOt2u/eu8YzcFnmPO5dUa1RJ6mkG', NULL, 0, 'c46258724hk@gmail.com', NULL, 'knt2yT2r', NULL, '2025-12-31 14:26:25', 230.00, 43, 'JW07BAHC', 'ALL', '2602:fbf1:b001::36', '美国', NULL);
-- 已有库升级ALTER TABLE ai_user ADD COLUMN dept_id bigint NULL DEFAULT NULL COMMENT '归属部门sys_dept.dept_id' AFTER country;
-- ---------------------------- -- ----------------------------
-- Table structure for ai_user_message -- Table structure for ai_user_message
@ -4190,6 +4195,7 @@ CREATE TABLE `sys_dept` (
`leader` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '负责人', `leader` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '负责人',
`phone` varchar(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '联系电话', `phone` varchar(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '联系电话',
`email` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '邮箱', `email` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '邮箱',
`byte_api_key` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'Byte API Key',
`status` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '部门状态0正常 1停用', `status` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '部门状态0正常 1停用',
`del_flag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '删除标志0代表存在 2代表删除', `del_flag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '删除标志0代表存在 2代表删除',
`create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '创建者', `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '创建者',
@ -4202,21 +4208,23 @@ CREATE TABLE `sys_dept` (
-- ---------------------------- -- ----------------------------
-- Records of sys_dept -- Records of sys_dept
-- ---------------------------- -- ----------------------------
INSERT INTO `sys_dept` VALUES (100, 0, '0', '若依科技', 0, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2025-11-09 01:56:46', '', NULL); INSERT INTO `sys_dept` VALUES (100, 0, '0', '若依科技', 0, '若依', '15888888888', 'ry@qq.com', NULL, '0', '0', 'admin', '2025-11-09 01:56:46', '', NULL);
INSERT INTO `sys_dept` VALUES (101, 100, '0,100', '深圳总公司', 1, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2025-11-09 01:56:47', '', NULL); INSERT INTO `sys_dept` VALUES (101, 100, '0,100', '深圳总公司', 1, '若依', '15888888888', 'ry@qq.com', NULL, '0', '0', 'admin', '2025-11-09 01:56:47', '', NULL);
INSERT INTO `sys_dept` VALUES (102, 100, '0,100', '长沙分公司', 2, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2025-11-09 01:56:47', '', NULL); INSERT INTO `sys_dept` VALUES (102, 100, '0,100', '长沙分公司', 2, '若依', '15888888888', 'ry@qq.com', NULL, '0', '0', 'admin', '2025-11-09 01:56:47', '', NULL);
INSERT INTO `sys_dept` VALUES (103, 101, '0,100,101', '研发部门', 1, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2025-11-09 01:56:47', '', NULL); INSERT INTO `sys_dept` VALUES (103, 101, '0,100,101', '研发部门', 1, '若依', '15888888888', 'ry@qq.com', NULL, '0', '0', 'admin', '2025-11-09 01:56:47', '', NULL);
INSERT INTO `sys_dept` VALUES (104, 101, '0,100,101', '市场部门', 2, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2025-11-09 01:56:47', '', NULL); INSERT INTO `sys_dept` VALUES (104, 101, '0,100,101', '市场部门', 2, '若依', '15888888888', 'ry@qq.com', NULL, '0', '0', 'admin', '2025-11-09 01:56:47', '', NULL);
INSERT INTO `sys_dept` VALUES (105, 101, '0,100,101', '测试部门', 3, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2025-11-09 01:56:48', '', NULL); INSERT INTO `sys_dept` VALUES (105, 101, '0,100,101', '测试部门', 3, '若依', '15888888888', 'ry@qq.com', NULL, '0', '0', 'admin', '2025-11-09 01:56:48', '', NULL);
INSERT INTO `sys_dept` VALUES (106, 101, '0,100,101', '财务部门', 4, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2025-11-09 01:56:48', '', NULL); INSERT INTO `sys_dept` VALUES (106, 101, '0,100,101', '财务部门', 4, '若依', '15888888888', 'ry@qq.com', NULL, '0', '0', 'admin', '2025-11-09 01:56:48', '', NULL);
INSERT INTO `sys_dept` VALUES (107, 101, '0,100,101', '运维部门', 5, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2025-11-09 01:56:49', '', NULL); INSERT INTO `sys_dept` VALUES (107, 101, '0,100,101', '运维部门', 5, '若依', '15888888888', 'ry@qq.com', NULL, '0', '0', 'admin', '2025-11-09 01:56:49', '', NULL);
INSERT INTO `sys_dept` VALUES (108, 102, '0,100,102', '市场部门', 1, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2025-11-09 01:56:49', '', NULL); INSERT INTO `sys_dept` VALUES (108, 102, '0,100,102', '市场部门', 1, '若依', '15888888888', 'ry@qq.com', NULL, '0', '0', 'admin', '2025-11-09 01:56:49', '', NULL);
INSERT INTO `sys_dept` VALUES (109, 102, '0,100,102', '财务部门', 2, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2025-11-09 01:56:49', '', NULL); INSERT INTO `sys_dept` VALUES (109, 102, '0,100,102', '财务部门', 2, '若依', '15888888888', 'ry@qq.com', NULL, '0', '0', 'admin', '2025-11-09 01:56:49', '', NULL);
INSERT INTO `sys_dept` VALUES (200, 100, '0,100', '胸部', 3, NULL, NULL, NULL, '0', '2', 'admin', '2025-11-25 13:07:38', '', NULL); INSERT INTO `sys_dept` VALUES (200, 100, '0,100', '胸部', 3, NULL, NULL, NULL, NULL, '0', '2', 'admin', '2025-11-25 13:07:38', '', NULL);
INSERT INTO `sys_dept` VALUES (201, 200, '0,100,200', '大奶', 1, NULL, NULL, NULL, '0', '2', 'admin', '2025-11-25 13:07:48', '', NULL); INSERT INTO `sys_dept` VALUES (201, 200, '0,100,200', '大奶', 1, NULL, NULL, NULL, NULL, '0', '2', 'admin', '2025-11-25 13:07:48', '', NULL);
INSERT INTO `sys_dept` VALUES (202, 201, '0,100,200,201', '水滴型', 1, NULL, NULL, NULL, '0', '2', 'admin', '2025-11-25 13:08:04', '', NULL); INSERT INTO `sys_dept` VALUES (202, 201, '0,100,200,201', '水滴型', 1, NULL, NULL, NULL, NULL, '0', '2', 'admin', '2025-11-25 13:08:04', '', NULL);
INSERT INTO `sys_dept` VALUES (203, 200, '0,100,200', '小奶', 2, NULL, NULL, NULL, '0', '2', 'admin', '2025-11-25 13:08:13', '', NULL); INSERT INTO `sys_dept` VALUES (203, 200, '0,100,200', '小奶', 2, NULL, NULL, NULL, NULL, '0', '2', 'admin', '2025-11-25 13:08:13', '', NULL);
INSERT INTO `sys_dept` VALUES (204, 201, '0,100,200,201', '粉色', 2, NULL, NULL, NULL, '0', '2', 'admin', '2025-11-25 13:08:25', '', NULL); INSERT INTO `sys_dept` VALUES (204, 201, '0,100,200,201', '粉色', 2, NULL, NULL, NULL, NULL, '0', '2', 'admin', '2025-11-25 13:08:25', '', NULL);
-- 已有数据库升级可执行ALTER TABLE sys_dept ADD COLUMN byte_api_key varchar(255) NULL DEFAULT NULL COMMENT 'Byte API Key' AFTER email;
-- ---------------------------- -- ----------------------------
-- Table structure for sys_dict_data -- Table structure for sys_dict_data
@ -4684,6 +4692,11 @@ INSERT INTO `sys_menu` VALUES (1058, '导入代码', 116, 4, '#', '', '', '', 1,
INSERT INTO `sys_menu` VALUES (1059, '预览代码', 116, 5, '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:preview', '#', 'admin', '2025-11-09 01:57:14', '', NULL, ''); INSERT INTO `sys_menu` VALUES (1059, '预览代码', 116, 5, '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:preview', '#', 'admin', '2025-11-09 01:57:14', '', NULL, '');
INSERT INTO `sys_menu` VALUES (1060, '生成代码', 116, 6, '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:code', '#', 'admin', '2025-11-09 01:57:14', '', NULL, ''); INSERT INTO `sys_menu` VALUES (1060, '生成代码', 116, 6, '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:code', '#', 'admin', '2025-11-09 01:57:14', '', NULL, '');
INSERT INTO `sys_menu` VALUES (2000, '综合管理', 0, 4, 'ai-manager', NULL, NULL, '', 1, 0, 'M', '0', '0', '', 'redis-list', 'admin', '2025-11-12 20:19:15', 'admin', '2025-11-20 20:06:49', ''); INSERT INTO `sys_menu` VALUES (2000, '综合管理', 0, 4, 'ai-manager', NULL, NULL, '', 1, 0, 'M', '0', '0', '', 'redis-list', 'admin', '2025-11-12 20:19:15', 'admin', '2025-11-20 20:06:49', '');
INSERT INTO `sys_menu` VALUES (2100, 'AI部门管理', 2003, 0, 'aiDept', 'ai/dept/index', NULL, '', 1, 0, 'C', '0', '0', 'ai:dept:list', 'tree', 'admin', '2026-03-30 10:00:00', '', NULL, '');
INSERT INTO `sys_menu` VALUES (2101, 'AI部门查询', 2100, 1, '', '', NULL, '', 1, 0, 'F', '0', '0', 'ai:dept:query', '#', 'admin', '2026-03-30 10:00:00', '', NULL, '');
INSERT INTO `sys_menu` VALUES (2102, 'AI部门新增', 2100, 2, '', '', NULL, '', 1, 0, 'F', '0', '0', 'ai:dept:add', '#', 'admin', '2026-03-30 10:00:00', '', NULL, '');
INSERT INTO `sys_menu` VALUES (2103, 'AI部门修改', 2100, 3, '', '', NULL, '', 1, 0, 'F', '0', '0', 'ai:dept:edit', '#', 'admin', '2026-03-30 10:00:00', '', NULL, '');
INSERT INTO `sys_menu` VALUES (2104, 'AI部门删除', 2100, 4, '', '', NULL, '', 1, 0, 'F', '0', '0', 'ai:dept:remove', '#', 'admin', '2026-03-30 10:00:00', '', NULL, '');
INSERT INTO `sys_menu` VALUES (2001, 'AI用户管理', 2003, 1, 'aiUser', 'ai/user/index', NULL, '', 1, 0, 'C', '0', '0', 'ai:user:list', 'user', 'admin', '2025-11-12 20:45:34', 'admin', '2025-11-13 22:19:09', ''); INSERT INTO `sys_menu` VALUES (2001, 'AI用户管理', 2003, 1, 'aiUser', 'ai/user/index', NULL, '', 1, 0, 'C', '0', '0', 'ai:user:list', 'user', 'admin', '2025-11-12 20:45:34', 'admin', '2025-11-13 22:19:09', '');
INSERT INTO `sys_menu` VALUES (2002, 'AI管理', 2000, 4, 'aiManager', 'ai/manager/index', NULL, '', 1, 0, 'C', '0', '0', 'ai:manager:list', 'online', 'admin', '2025-11-13 19:18:54', 'admin', '2025-11-13 22:49:28', ''); INSERT INTO `sys_menu` VALUES (2002, 'AI管理', 2000, 4, 'aiManager', 'ai/manager/index', NULL, '', 1, 0, 'C', '0', '0', 'ai:manager:list', 'online', 'admin', '2025-11-13 19:18:54', 'admin', '2025-11-13 22:49:28', '');
INSERT INTO `sys_menu` VALUES (2003, '用户管理', 2000, 1, 'aiUserManger', NULL, NULL, '', 1, 0, 'M', '0', '0', NULL, 'peoples', 'admin', '2025-11-13 22:18:42', '', NULL, ''); INSERT INTO `sys_menu` VALUES (2003, '用户管理', 2000, 1, 'aiUserManger', NULL, NULL, '', 1, 0, 'M', '0', '0', NULL, 'peoples', 'admin', '2025-11-13 22:18:42', '', NULL, '');

BIN
接口文档.pdf Normal file

Binary file not shown.