初步实现,会员临期提醒功能,待完善
This commit is contained in:
@@ -3,15 +3,9 @@
|
||||
- 采用SpringBoot3.x、Shiro、MyBatis-Plus、Vue3、TypeScript、Element Plus、Vue Router、Pinia、Axios、Vite框架,开发的一套权限系统,极低门槛,拿来即用。设计之初,就非常注重安全性,为企业系统保驾护航,让一切都变得如此简单。
|
||||
- 提供了代码生成器,只需编写30%左右代码,其余的代码交给系统自动生成,可快速完成开发任务
|
||||
- 支持MySQL、达梦、Oracle、SQL Server、PostgreSQL等主流数据库
|
||||
- 演示地址:http://demo.open.renren.io/renren-security (账号密码:admin/admin)
|
||||
|
||||
<br>
|
||||
|
||||
### 微信交流群
|
||||
我们提供了微信交流群,扫码下面的二维码,关注【人人开源】公众号,回复【加群】,即可根据提示加入微信群!
|
||||
<br><br>
|
||||

|
||||
|
||||
<br>
|
||||
|
||||
### 具有如下特点
|
||||
@@ -108,19 +102,3 @@ renren-security
|
||||
- 账号密码:admin/admin
|
||||
<br>
|
||||
|
||||

|
||||
|
||||
<br>
|
||||
|
||||

|
||||
|
||||
<br>
|
||||
|
||||
### 如何交流、反馈、参与贡献?
|
||||
- 开发文档:https://www.renren.io/guide/security
|
||||
- Gitee仓库:https://gitee.com/renrenio/renren-security
|
||||
- GitCode仓库:https://gitcode.com/renrenio/renren-security
|
||||
- [人人开源](https://www.renren.io):https://www.renren.io
|
||||
- 如需关注项目最新动态,请Watch、Star项目,同时也是对项目最好的支持
|
||||
<br>
|
||||
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
package top.iletter.modules.baitutools.controller;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.enums.ParameterIn;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import top.iletter.common.annotation.LogOperation;
|
||||
import top.iletter.common.constant.Constant;
|
||||
import top.iletter.common.page.PageData;
|
||||
import top.iletter.common.utils.ExcelUtils;
|
||||
import top.iletter.common.utils.Result;
|
||||
import top.iletter.common.validator.AssertUtils;
|
||||
import top.iletter.common.validator.ValidatorUtils;
|
||||
import top.iletter.common.validator.group.AddGroup;
|
||||
import top.iletter.common.validator.group.DefaultGroup;
|
||||
import top.iletter.common.validator.group.UpdateGroup;
|
||||
import top.iletter.modules.baitutools.dto.DlRenewalRemindDTO;
|
||||
import top.iletter.modules.baitutools.excel.DlRenewalRemindExcel;
|
||||
import top.iletter.modules.baitutools.service.DlRenewalRemindService;
|
||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.Parameters;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* 临期续费
|
||||
*
|
||||
* @author dellevin dellevin99@gmail.com
|
||||
* @since 1.0.0 2026-02-04
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("baitutools/dlrenewalremind")
|
||||
@Tag(name="临期续费")
|
||||
public class DlRenewalRemindController {
|
||||
private static final Logger log = LoggerFactory.getLogger(DlRenewalRemindController.class);
|
||||
@Autowired
|
||||
private DlRenewalRemindService dlRenewalRemindService;
|
||||
|
||||
@GetMapping("page")
|
||||
@Operation(summary = "分页")
|
||||
@Parameters({
|
||||
@Parameter(name = Constant.PAGE, description = "当前页码,从1开始", in = ParameterIn.QUERY, required = true, ref="int") ,
|
||||
@Parameter(name = Constant.LIMIT, description = "每页显示记录数", in = ParameterIn.QUERY,required = true, ref="int") ,
|
||||
@Parameter(name = Constant.ORDER_FIELD, description = "排序字段", in = ParameterIn.QUERY, ref="String") ,
|
||||
@Parameter(name = Constant.ORDER, description = "排序方式,可选值(asc、desc)", in = ParameterIn.QUERY, ref="String"),
|
||||
@Parameter(name = "名称", description = "名称搜索", in = ParameterIn.QUERY, ref="String")
|
||||
})
|
||||
@RequiresPermissions("baitutools:dlrenewalremind:page")
|
||||
public Result<PageData<DlRenewalRemindDTO>> page(@Parameter(hidden = true) @RequestParam Map<String, Object> params){
|
||||
PageData<DlRenewalRemindDTO> page = dlRenewalRemindService.page(params);
|
||||
|
||||
return new Result<PageData<DlRenewalRemindDTO>>().ok(page);
|
||||
}
|
||||
|
||||
@GetMapping("{id}")
|
||||
@Operation(summary = "信息")
|
||||
@RequiresPermissions("baitutools:dlrenewalremind:info")
|
||||
public Result<DlRenewalRemindDTO> get(@PathVariable("id") Long id){
|
||||
DlRenewalRemindDTO data = dlRenewalRemindService.get(id);
|
||||
|
||||
return new Result<DlRenewalRemindDTO>().ok(data);
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
@Operation(summary = "保存")
|
||||
@LogOperation("保存")
|
||||
@RequiresPermissions("baitutools:dlrenewalremind:save")
|
||||
public Result save(@RequestBody DlRenewalRemindDTO dto){
|
||||
log.info( ">>>>>>>>>"+dto.toString());
|
||||
//效验数据
|
||||
ValidatorUtils.validateEntity(dto, AddGroup.class, DefaultGroup.class);
|
||||
|
||||
dlRenewalRemindService.save(dto);
|
||||
|
||||
return new Result();
|
||||
}
|
||||
|
||||
@PutMapping
|
||||
@Operation(summary = "修改")
|
||||
@LogOperation("修改")
|
||||
@RequiresPermissions("baitutools:dlrenewalremind:update")
|
||||
public Result update(@RequestBody DlRenewalRemindDTO dto){
|
||||
//效验数据
|
||||
ValidatorUtils.validateEntity(dto, UpdateGroup.class, DefaultGroup.class);
|
||||
|
||||
dlRenewalRemindService.update(dto);
|
||||
|
||||
return new Result();
|
||||
}
|
||||
|
||||
@DeleteMapping
|
||||
@Operation(summary = "删除")
|
||||
@LogOperation("删除")
|
||||
@RequiresPermissions("baitutools:dlrenewalremind:delete")
|
||||
public Result delete(@RequestBody Long[] ids){
|
||||
//效验数据
|
||||
AssertUtils.isArrayEmpty(ids, "id");
|
||||
|
||||
dlRenewalRemindService.delete(ids);
|
||||
|
||||
return new Result();
|
||||
}
|
||||
|
||||
@GetMapping("export")
|
||||
@Operation(summary = "导出")
|
||||
@LogOperation("导出")
|
||||
@RequiresPermissions("baitutools:dlrenewalremind:export")
|
||||
public void export(@Parameter(hidden = true) @RequestParam Map<String, Object> params, HttpServletResponse response) throws Exception {
|
||||
List<DlRenewalRemindDTO> list = dlRenewalRemindService.list(params);
|
||||
|
||||
ExcelUtils.exportExcelToTarget(response, null, "临期续费", list, DlRenewalRemindExcel.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package top.iletter.modules.baitutools.dao;
|
||||
|
||||
import top.iletter.common.dao.BaseDao;
|
||||
import top.iletter.modules.baitutools.entity.DlRenewalRemindEntity;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 临期续费
|
||||
*
|
||||
* @author dellevin dellevin99@gmail.com
|
||||
* @since 1.0.0 2026-02-04
|
||||
*/
|
||||
@Mapper
|
||||
public interface DlRenewalRemindDao extends BaseDao<DlRenewalRemindEntity> {
|
||||
/**
|
||||
* 获取信息
|
||||
* @param params 查询参数 页码: page 每页条数: limit
|
||||
* 排序字段: orderField 升/降序: order 区域代码: regionCode
|
||||
* 页面搜索关键字: keyword 供应商名称: supplierName ...
|
||||
* @return 符合条件的中标信息列表
|
||||
*/
|
||||
List<DlRenewalRemindEntity> getList(Map<String, Object> params);
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package top.iletter.modules.baitutools.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.media.SchemaProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
/**
|
||||
* 临期续费
|
||||
*
|
||||
* @author dellevin dellevin99@gmail.com
|
||||
* @since 1.0.0 2026-02-04
|
||||
*/
|
||||
@Data
|
||||
@Schema(name = "临期续费")
|
||||
public class DlRenewalRemindDTO implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@SchemaProperty(name = "")
|
||||
private String id;
|
||||
|
||||
@SchemaProperty(name = " 提供商:阿里/腾讯/网易/百度/")
|
||||
private String provider;
|
||||
|
||||
@SchemaProperty(name = "名称")
|
||||
private String name;
|
||||
|
||||
@SchemaProperty(name = "备注")
|
||||
private String remark;
|
||||
|
||||
@SchemaProperty(name = "其他信息json形式")
|
||||
private String otherInfo;
|
||||
|
||||
@SchemaProperty(name = "续费方式1一次性 2月费 3季费 4年费")
|
||||
private String renewalType;
|
||||
|
||||
@SchemaProperty(name = "具体续费日期:每 月/季/年 的XX号 1~31")
|
||||
private String renewalDate;
|
||||
|
||||
@SchemaProperty(name = "到期时间 年-月-日")
|
||||
private Date expireTime;
|
||||
|
||||
@SchemaProperty(name = "预留字段")
|
||||
private String mark1;
|
||||
|
||||
@SchemaProperty(name = "预留字段")
|
||||
private String mark2;
|
||||
|
||||
@SchemaProperty(name = "预留字段")
|
||||
private String mark3;
|
||||
|
||||
@SchemaProperty(name = "")
|
||||
private Date createDate;
|
||||
|
||||
@SchemaProperty(name = "")
|
||||
private String createUser;
|
||||
|
||||
@SchemaProperty(name = "")
|
||||
private Date updateDate;
|
||||
|
||||
@SchemaProperty(name = "")
|
||||
private String updateUser;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package top.iletter.modules.baitutools.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 临期续费
|
||||
*
|
||||
* @author dellevin dellevin99@gmail.com
|
||||
* @since 1.0.0 2026-02-04
|
||||
*/
|
||||
@Data
|
||||
@TableName("dl_renewal_remind")
|
||||
public class DlRenewalRemindEntity {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private String id;
|
||||
/**
|
||||
* 提供商:阿里/腾讯/网易/百度/
|
||||
*/
|
||||
private String provider;
|
||||
/**
|
||||
* 名称
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
/**
|
||||
* 其他信息json形式
|
||||
*/
|
||||
private String otherInfo;
|
||||
/**
|
||||
* 续费方式
|
||||
|
||||
1一次性
|
||||
2月费
|
||||
3季费
|
||||
4年费
|
||||
*/
|
||||
private String renewalType;
|
||||
/**
|
||||
* 具体续费日期:每 月/季/年 的XX号 1~31
|
||||
*/
|
||||
private String renewalDate;
|
||||
/**
|
||||
* 到期时间 年-月-日
|
||||
*/
|
||||
private Date expireTime;
|
||||
/**
|
||||
* 预留字段
|
||||
*/
|
||||
private String mark1;
|
||||
/**
|
||||
* 预留字段
|
||||
*/
|
||||
private String mark2;
|
||||
/**
|
||||
* 预留字段
|
||||
*/
|
||||
private String mark3;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private Date createDate;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private String createUser;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private Date updateDate;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private String updateUser;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package top.iletter.modules.baitutools.excel;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import com.alibaba.excel.annotation.write.style.ColumnWidth;
|
||||
import com.alibaba.excel.annotation.write.style.ContentRowHeight;
|
||||
import com.alibaba.excel.annotation.write.style.HeadRowHeight;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 临期续费
|
||||
*
|
||||
* @author dellevin dellevin99@gmail.com
|
||||
* @since 1.0.0 2026-02-04
|
||||
*/
|
||||
@Data
|
||||
public class DlRenewalRemindExcel {
|
||||
@ExcelProperty(value = "")
|
||||
private String id;
|
||||
@ExcelProperty(value = "提供商:阿里/腾讯/网易/百度/")
|
||||
private String provider;
|
||||
@ExcelProperty(value = "名称")
|
||||
private String name;
|
||||
@ExcelProperty(value = "备注")
|
||||
private String remark;
|
||||
@ExcelProperty(value = "其他信息json形式")
|
||||
private String otherInfo;
|
||||
@ExcelProperty(value = "续费方式1一次性 2月费 3季费 4年费")
|
||||
private String renewalType;
|
||||
@ExcelProperty(value = "具体续费日期:每 月/季/年 的XX号 1~31")
|
||||
private String renewalDate;
|
||||
@ExcelProperty(value = "到期时间 年-月-日")
|
||||
private Date expireTime;
|
||||
@ExcelProperty(value = "预留字段")
|
||||
private String mark1;
|
||||
@ExcelProperty(value = "预留字段")
|
||||
private String mark2;
|
||||
@ExcelProperty(value = "预留字段")
|
||||
private String mark3;
|
||||
@ExcelProperty(value = "")
|
||||
private Date createDate;
|
||||
@ExcelProperty(value = "")
|
||||
private String createUser;
|
||||
@ExcelProperty(value = "")
|
||||
private Date updateDate;
|
||||
@ExcelProperty(value = "")
|
||||
private String updateUser;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package top.iletter.modules.baitutools.service;
|
||||
|
||||
import top.iletter.common.service.CrudService;
|
||||
import top.iletter.modules.baitutools.dto.DlRenewalRemindDTO;
|
||||
import top.iletter.modules.baitutools.entity.DlRenewalRemindEntity;
|
||||
|
||||
/**
|
||||
* 临期续费
|
||||
*
|
||||
* @author dellevin dellevin99@gmail.com
|
||||
* @since 1.0.0 2026-02-04
|
||||
*/
|
||||
public interface DlRenewalRemindService extends CrudService<DlRenewalRemindEntity, DlRenewalRemindDTO> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package top.iletter.modules.baitutools.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import top.iletter.common.page.PageData;
|
||||
import top.iletter.common.service.impl.CrudServiceImpl;
|
||||
import top.iletter.modules.baitutools.dao.DlRenewalRemindDao;
|
||||
import top.iletter.modules.baitutools.dto.DlRenewalRemindDTO;
|
||||
import top.iletter.modules.baitutools.entity.DlRenewalRemindEntity;
|
||||
import top.iletter.modules.baitutools.service.DlRenewalRemindService;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 临期续费
|
||||
*
|
||||
* @author dellevin dellevin99@gmail.com
|
||||
* @since 1.0.0 2026-02-04
|
||||
*/
|
||||
@Service
|
||||
public class DlRenewalRemindServiceImpl extends CrudServiceImpl<DlRenewalRemindDao, DlRenewalRemindEntity, DlRenewalRemindDTO> implements DlRenewalRemindService {
|
||||
|
||||
@Override
|
||||
public QueryWrapper<DlRenewalRemindEntity> getWrapper(Map<String, Object> params){
|
||||
String id = (String)params.get("id");
|
||||
|
||||
QueryWrapper<DlRenewalRemindEntity> wrapper = new QueryWrapper<>();
|
||||
wrapper.eq(StrUtil.isNotBlank(id), "id", id);
|
||||
|
||||
return wrapper;
|
||||
}
|
||||
@Override
|
||||
public PageData<DlRenewalRemindDTO> page(Map<String, Object> params) {
|
||||
IPage<DlRenewalRemindEntity> page = getPage(params, "create_date", false);
|
||||
|
||||
List<DlRenewalRemindEntity> list = baseDao.getList(params);
|
||||
return getPageData(list, page.getTotal(), DlRenewalRemindDTO.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package top.iletter.modules.job.task;
|
||||
|
||||
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
/**
|
||||
* 临期提醒,检查有哪个服务即将过期,传入参数为json形式
|
||||
* {
|
||||
* agoDate:'10', // 提前提醒时间
|
||||
* isEmail:'true' // 是否开启邮件通知
|
||||
* }
|
||||
*/
|
||||
@Component("ExpirationDateReminder")
|
||||
public class ExpirationDateReminder implements ITask{
|
||||
private Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
@Override
|
||||
public void run(String params){
|
||||
logger.debug("Task定时任务正在执行,参数为:{}", params);
|
||||
}
|
||||
}
|
||||
@@ -42,8 +42,9 @@ spring:
|
||||
stat-view-servlet:
|
||||
enabled: true
|
||||
url-pattern: /druid/*
|
||||
#login-username: admin
|
||||
#login-password: admin
|
||||
allow: ""
|
||||
# login-username: admin
|
||||
# login-password: admin
|
||||
#达梦数据库,需要注释掉,其他数据库可以打开
|
||||
# filter:
|
||||
# stat:
|
||||
|
||||
@@ -24,7 +24,7 @@ knife4j:
|
||||
spring:
|
||||
# 环境 dev|test|prod
|
||||
profiles:
|
||||
active: prod
|
||||
active: dev
|
||||
messages:
|
||||
encoding: UTF-8
|
||||
basename: i18n/messages
|
||||
@@ -60,7 +60,7 @@ renren:
|
||||
mybatis-plus:
|
||||
mapper-locations: classpath*:/mapper/**/*.xml
|
||||
#实体扫描,多个package用逗号或者分号分隔
|
||||
typeAliasesPackage: io.renren.modules.*.entity
|
||||
typeAliasesPackage: top.iletter.modules.*.entity
|
||||
global-config:
|
||||
#数据库相关配置
|
||||
db-config:
|
||||
|
||||
@@ -8,14 +8,14 @@
|
||||
<springProfile name="dev,test">
|
||||
<logger name="org.springframework.web" level="INFO"/>
|
||||
<logger name="org.springboot.sample" level="INFO" />
|
||||
<logger name="io.renren" level="DEBUG" />
|
||||
<logger name="top.iletter" level="DEBUG" />
|
||||
</springProfile>
|
||||
|
||||
<!-- 生产环境 -->
|
||||
<springProfile name="prod">
|
||||
<logger name="org.springframework.web" level="ERROR"/>
|
||||
<logger name="org.springboot.sample" level="ERROR" />
|
||||
<logger name="io.renren" level="ERROR" />
|
||||
<logger name="top.iletter" level="ERROR" />
|
||||
</springProfile>
|
||||
|
||||
</configuration>
|
||||
@@ -0,0 +1,33 @@
|
||||
<?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="top.iletter.modules.baitutools.dao.DlRenewalRemindDao">
|
||||
|
||||
<resultMap type="top.iletter.modules.baitutools.entity.DlRenewalRemindEntity" id="dlRenewalRemindMap">
|
||||
<result property="id" column="id"/>
|
||||
<result property="provider" column="provider"/>
|
||||
<result property="name" column="name"/>
|
||||
<result property="remark" column="remark"/>
|
||||
<result property="otherInfo" column="other_info"/>
|
||||
<result property="renewalType" column="renewal_type"/>
|
||||
<result property="renewalDate" column="renewal_date"/>
|
||||
<result property="expireTime" column="expire_time"/>
|
||||
<result property="mark1" column="mark1"/>
|
||||
<result property="mark2" column="mark2"/>
|
||||
<result property="mark3" column="mark3"/>
|
||||
<result property="createDate" column="create_date"/>
|
||||
<result property="createUser" column="create_user"/>
|
||||
<result property="updateDate" column="update_date"/>
|
||||
<result property="updateUser" column="update_user"/>
|
||||
</resultMap>
|
||||
<!-- 获取分页查询 -->
|
||||
<select id="getList" resultType="top.iletter.modules.baitutools.entity.DlRenewalRemindEntity">
|
||||
SELECT * FROM dl_renewal_remind
|
||||
<where>
|
||||
<if test="keywordName != null and keywordName.trim() != ''">
|
||||
AND locate(#{keywordName} , `name` )
|
||||
</if>
|
||||
</where>
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 293 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 299 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 4.2 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 27 KiB |
@@ -8,14 +8,14 @@
|
||||
<springProfile name="dev,test">
|
||||
<logger name="org.springframework.web" level="INFO"/>
|
||||
<logger name="org.springboot.sample" level="INFO" />
|
||||
<logger name="io.renren" level="DEBUG" />
|
||||
<logger name="top.iletter" level="DEBUG" />
|
||||
</springProfile>
|
||||
|
||||
<!-- 生产环境 -->
|
||||
<springProfile name="prod">
|
||||
<logger name="org.springframework.web" level="ERROR"/>
|
||||
<logger name="org.springboot.sample" level="ERROR" />
|
||||
<logger name="io.renren" level="ERROR" />
|
||||
<logger name="top.iletter" level="ERROR" />
|
||||
</springProfile>
|
||||
|
||||
</configuration>
|
||||
@@ -53,7 +53,7 @@ public class SysGeneratorController {
|
||||
byte[] data = sysGeneratorService.generatorCode(tables.split(","));
|
||||
|
||||
response.reset();
|
||||
response.setHeader("Content-Disposition", "attachment; filename=\"renren.zip\"");
|
||||
response.setHeader("Content-Disposition", "attachment; filename=\"baitu_code.zip\"");
|
||||
response.addHeader("Content-Length", "" + data.length);
|
||||
response.setContentType("application/octet-stream; charset=UTF-8");
|
||||
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
#\u4EE3\u7801\u751F\u6210\u5668\uFF0C\u914D\u7F6E\u4FE1\u606F
|
||||
|
||||
#\u5305\u540D
|
||||
package=io.renren
|
||||
moduleName=demo
|
||||
#\u4F5C\u8005
|
||||
author=Mark
|
||||
|
||||
package=top.iletter
|
||||
moduleName=baitutools
|
||||
author=dellevin
|
||||
#Email
|
||||
email=sunlightcs@gmail.com
|
||||
#\u8868\u524D\u7F00(\u7C7B\u540D\u4E0D\u4F1A\u5305\u542B\u8868\u524D\u7F00)
|
||||
email=dellevin99@gmail.com
|
||||
#???(?????????)
|
||||
tablePrefix=tb_
|
||||
version=1.0.0
|
||||
|
||||
|
||||
#\u7C7B\u578B\u8F6C\u6362\uFF0C\u914D\u7F6E\u4FE1\u606F
|
||||
# ?????????
|
||||
tinyint=Integer
|
||||
smallint=Integer
|
||||
mediumint=Integer
|
||||
|
||||
@@ -6,6 +6,6 @@
|
||||
|
||||
<logger name="org.springframework.web" level="INFO"/>
|
||||
<logger name="org.springboot.sample" level="INFO" />
|
||||
<logger name="io.renren" level="DEBUG" />
|
||||
<logger name="top.iletter" level="DEBUG" />
|
||||
|
||||
</configuration>
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>人人代码生成器</title>
|
||||
<title>代码生成器</title>
|
||||
<!-- Tell the browser to be responsive to screen width -->
|
||||
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
|
||||
<link rel="stylesheet" href="css/bootstrap.min.css">
|
||||
@@ -27,9 +27,9 @@
|
||||
<header class="main-header">
|
||||
<a href="javascript:void(0);" class="logo">
|
||||
<!-- mini logo for sidebar mini 50x50 pixels -->
|
||||
<span class="logo-mini"><b>人人</b></span>
|
||||
<span class="logo-mini"><b>BAITU</b></span>
|
||||
<!-- logo for regular state and mobile devices -->
|
||||
<span class="logo-lg"><b>人人代码生成器</b></span>
|
||||
<span class="logo-lg"><b>代码生成器</b></span>
|
||||
</a>
|
||||
<!-- Header Navbar: style can be found in header.less -->
|
||||
<nav class="navbar navbar-static-top" role="navigation">
|
||||
@@ -40,8 +40,7 @@
|
||||
<div style="float:left;color:#fff;padding:15px 10px;">代码的搬运工</div>
|
||||
<div class="navbar-custom-menu">
|
||||
<ul class="nav navbar-nav">
|
||||
<li><a href="javascript:;" @click="donate"><i class="fa fa-jpy"></i> 捐赠作者</a></li>
|
||||
<li><a href="https://www.renren.io" target="_blank"><i class="fa fa-home"></i> 人人开源</a></li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
@@ -61,7 +60,7 @@
|
||||
<a href="javascript:;"><i class="fa fa-cog"></i><span>代码生成器</span><i class="fa fa-angle-left pull-right"></i></a>
|
||||
<ul class="treeview-menu menu-open" style="display: block;">
|
||||
<li class="active"><a href="#main.html"><i class="fa fa-rocket"></i> 控制台</a></li>
|
||||
<li><a href="#generator.html"><i class="fa fa-rocket"></i> renren-security</a></li>
|
||||
<li><a href="#generator.html"><i class="fa fa-rocket"></i>数据库</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -11,18 +11,7 @@
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">基本信息</div>
|
||||
<div style="padding: 10px 0 20px 10px;">
|
||||
<h3> 获取帮助</h3>
|
||||
<ul>
|
||||
<li>Git地址:<a href="https://gitee.com/renrenio/renren-security" target="_blank">https://gitee.com/renrenio/renren-security</a></li>
|
||||
<li>官方社区:<a href="https://www.renren.io/community" target="_blank">https://www.renren.io/community</a></li>
|
||||
<li>如需寻求帮助、项目建议、技术讨论等,请移步到官方社区,我会在第一时间进行解答或回复</li>
|
||||
<li>如需关注项目最新动态,请Watch、Star项目,同时也是对项目最好的支持</li>
|
||||
</ul>
|
||||
<h3>官方微信群</h3>
|
||||
<ul>
|
||||
<li>扫码下面的二维码,关注【人人开源】公众号,回复【加群】,即可根据提示加入微信群!</li>
|
||||
<li><img src="https://cdn.renren.io/f5cef202207132229319338.jpg" alt="微信群" /></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
NODE_ENV=development
|
||||
VITE_APP_API=http://152.136.153.72:27005/admin
|
||||
# VITE_APP_API=http://10.8.0.3/api/admin
|
||||
# VITE_APP_API=http://152.136.153.72:27005/admin
|
||||
VITE_APP_API=http://10.8.0.3:8888/admin
|
||||
|
||||
@@ -21,28 +21,3 @@ npm install
|
||||
# 启动项目
|
||||
npm run dev
|
||||
```
|
||||
|
||||
> 如网络不稳定,安装时出错或进度过慢!请移步 [cnpm](https://npmmirror.com/) 淘宝镜像进行安装。
|
||||
|
||||
启动完成后,会自动打开浏览器访问 [http://localhost:8001](http://localhost:8001),如您看到下面的页面代表`前端项目`运行成功!因为前后端分离项目,需保证`前端项目`和`后台项目`分别独立正常运行。
|
||||
|
||||
请留意下面的页面,其中`验证码`未能正常显示,控制台有`API请求`报错信息!这时需检查`后台项目`是否正常运行。
|
||||
|
||||
|
||||
|
||||
## 如何交流、反馈、参与贡献?
|
||||
- 开发文档:https://www.renren.io/guide/security
|
||||
- 官方社区:https://www.renren.io/community
|
||||
- [人人开源](https://www.renren.io):https://www.renren.io
|
||||
- 如需关注项目最新动态,请Watch、Star项目,同时也是对项目最好的支持
|
||||
- 技术讨论、二次开发等咨询、问题和建议,请移步到官方社区,我会在第一时间进行解答和回复!
|
||||
- 微信扫码并关注【人人开源】,获得项目最新动态及更新提醒<br>
|
||||
|
||||
<br>
|
||||
|
||||
## 微信交流群
|
||||
我们提供了微信交流群,扫码下面的二维码,关注【人人开源】公众号,回复【加群】,即可根据提示加入微信群!
|
||||
<br><br>
|
||||
|
||||
<br>
|
||||
<br>
|
||||
|
||||
@@ -28,7 +28,7 @@ export default defineComponent({
|
||||
<span :class="`rr-header-ctx-logo-img-wrap ${'enabled-logo-' + app.enabledLogo}`">
|
||||
<!-- 支持显示图片logo或者产品名称缩写,二选一模式,通过注释开启功能,app.enabledLogo控制正常模式下图片logo是否显示,如果有图片logo,收起状态会强制显示图片logo -->
|
||||
<!-- <img :src="props.logoUrl" class="rr-header-ctx-logo-img" :alt="props.logoName" /> -->
|
||||
<span>人人</span>
|
||||
<span>DL</span>
|
||||
<span class="rr-header-ctx-logo-line"></span>
|
||||
</span>
|
||||
<span class="rr-header-ctx-logo-text">{{ props.logoName }}</span>
|
||||
|
||||
@@ -1,437 +0,0 @@
|
||||
<template>
|
||||
<div class="tts-app">
|
||||
<el-card class="box-card">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>GPT-SoVITS 语音合成</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- API 配置 -->
|
||||
<!-- <div class="config-section">
|
||||
<h3>API 配置</h3>
|
||||
<el-form :model="apiConfig" label-width="120px">
|
||||
<el-form-item label="API 地址">
|
||||
<el-input v-model="apiConfig.baseUrl" placeholder="例如: http://127.0.0.1:9880" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div> -->
|
||||
|
||||
<!-- 角色选择 -->
|
||||
<div class="character-section">
|
||||
<h3>角色选择</h3>
|
||||
<el-form label-width="120px">
|
||||
<el-form-item label="选择角色">
|
||||
<el-select
|
||||
v-model="selectedCharacterId"
|
||||
placeholder="请选择角色"
|
||||
@change="switchModelByCharacter"
|
||||
:loading="modelSwitching.gpt || modelSwitching.sovits"
|
||||
>
|
||||
<el-option
|
||||
v-for="char in availableCharacters"
|
||||
:key="char.id"
|
||||
:label="char.name"
|
||||
:value="char.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<!-- 合成参数 -->
|
||||
<div class="params-section">
|
||||
<h3>合成参数</h3>
|
||||
<el-form :model="ttsParams" :rules="ttsRules" ref="ttsFormRef" label-width="150px" :disabled="isGenerating">
|
||||
<el-form-item label="待合成提示文本" prop="text">
|
||||
<el-input
|
||||
v-model="ttsParams.text"
|
||||
type="textarea"
|
||||
:rows="4"
|
||||
placeholder="请输入要合成的文本..."
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="提示文本语言" prop="prompt_lang">
|
||||
<el-select v-model="ttsParams.prompt_lang" placeholder="请选择提示文本语言">
|
||||
<el-option label="中文" value="zh" />
|
||||
<el-option label="英文" value="en" />
|
||||
<el-option label="日文" value="ja" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
|
||||
<el-form-item label="生成语音语言" prop="text_lang">
|
||||
<el-select v-model="ttsParams.text_lang" placeholder="请选择文本语言">
|
||||
<el-option label="中文" value="zh" />
|
||||
<el-option label="英文" value="en" />
|
||||
<el-option label="日文" value="ja" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<!-- 参考音频路径现在由 selectedCharacter 决定 -->
|
||||
<!-- <el-form-item label="参考音频路径" prop="ref_audio_path">
|
||||
<el-input
|
||||
v-model="ttsParams.ref_audio_path"
|
||||
readonly
|
||||
placeholder="由角色自动设置"
|
||||
:disabled="true"
|
||||
/>
|
||||
</el-form-item> -->
|
||||
<!-- 提示文本 (可选) 现在由 selectedCharacter 决定 -->
|
||||
<!-- <el-form-item label="提示文本 (可选)">
|
||||
<el-input
|
||||
v-model="ttsParams.prompt_text"
|
||||
type="textarea"
|
||||
:rows="2"
|
||||
readonly
|
||||
placeholder="由角色自动设置 (如果配置)"
|
||||
:disabled="true"
|
||||
/>
|
||||
</el-form-item> -->
|
||||
|
||||
<el-form-item label="文本分割方式">
|
||||
<el-select v-model="ttsParams.text_split_method">
|
||||
<el-option label="不切" value="cut0" />
|
||||
<el-option label="按。切" value="cut1" />
|
||||
<el-option label="按,。切" value="cut2" />
|
||||
<el-option label="按?!切" value="cut3" />
|
||||
<el-option label="按,。?!切" value="cut4" />
|
||||
<el-option label="按每行切" value="cut5" />
|
||||
<el-option label="按换行切" value="cut6" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="流式传输">
|
||||
<el-switch v-model="ttsParams.streaming_mode" />
|
||||
</el-form-item> -->
|
||||
<!-- <el-form-item label="批处理大小">
|
||||
<el-input-number v-model="ttsParams.batch_size" :min="1" :max="10" />
|
||||
</el-form-item> -->
|
||||
<!-- <el-form-item label="Top-K">
|
||||
<el-input-number v-model="ttsParams.top_k" :min="1" :max="100" />
|
||||
</el-form-item> -->
|
||||
<!-- <el-form-item label="Top-P">
|
||||
<el-slider v-model="ttsParams.top_p" :min="0" :max="1" :step="0.01" />
|
||||
</el-form-item> -->
|
||||
<el-form-item label="音频随机参数">
|
||||
<el-slider v-model="ttsParams.temperature" :min="0" :max="2" :step="0.01" />
|
||||
</el-form-item>
|
||||
<el-form-item label="音频语速倍率">
|
||||
<el-slider v-model="ttsParams.speed_factor" :min="0.1" :max="3" :step="0.1" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<!-- 控制按钮 -->
|
||||
<div class="controls-section">
|
||||
<el-button type="primary" @click="synthesize" :loading="isGenerating">
|
||||
{{ isGenerating ? '生成中...' : '合成语音' }}
|
||||
</el-button>
|
||||
<el-button @click="stopGeneration" :disabled="!isGenerating">停止</el-button>
|
||||
<el-button @click="clearAudio">清空音频</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 音频播放 -->
|
||||
<div class="audio-section" v-if="audioUrl">
|
||||
<h3>合成结果</h3>
|
||||
<audio :src="audioUrl" controls class="audio-player" />
|
||||
</div>
|
||||
|
||||
<!-- 日志 -->
|
||||
<div class="log-section">
|
||||
<h3>日志</h3>
|
||||
<pre class="log-content">{{ log }}</pre>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive, computed, onUnmounted } from 'vue';
|
||||
import { ElMessage, FormInstance, FormRules } from 'element-plus';
|
||||
|
||||
// API 配置
|
||||
const apiConfig = reactive({
|
||||
baseUrl: 'http://127.0.0.1:9880', // 默认地址
|
||||
});
|
||||
|
||||
// 可用角色列表 (在这里添加你的角色)
|
||||
const availableCharacters = [
|
||||
{
|
||||
id: 'yier',
|
||||
name: '一二(yier)',
|
||||
gptPath: 'E:\\AI\\GPT-SoVITS-v4-20250529\\GPT_weights_v2\\yier-e20.ckpt',
|
||||
sovitsPath: 'E:\\AI\\GPT-SoVITS-v4-20250529\\SoVITS_weights_v2\\yier_e8_s144.pth',
|
||||
refAudioPath: 'D:\\UserData\\Desktop\\声音素材\\temp\\yier001.mp3',
|
||||
// promptText: 'This is a prompt for 一二.' // 示例:可选的提示文本
|
||||
},
|
||||
{
|
||||
id: 'bubu',
|
||||
name: '布布(bubu)',
|
||||
gptPath: 'E:\\AI\\GPT-SoVITS-v4-20250529\\GPT_weights_v2\\bubu-e20.ckpt',
|
||||
sovitsPath: 'E:\\AI\\GPT-SoVITS-v4-20250529\\SoVITS_weights_v2\\bubu_e8_s136.pth',
|
||||
refAudioPath: 'D:\\UserData\\Desktop\\声音素材\\temp\\bubu001.wav'
|
||||
},
|
||||
];
|
||||
|
||||
// 当前选中的角色 ID
|
||||
const selectedCharacterId = ref('yier'); // 默认选择一二
|
||||
|
||||
// 计算属性:根据 ID 获取当前选中的角色信息
|
||||
const currentCharacter = computed(() => {
|
||||
return availableCharacters.find(char => char.id === selectedCharacterId.value) || null;
|
||||
});
|
||||
|
||||
// TTS 参数
|
||||
const ttsParams = reactive({
|
||||
text: '欢迎来到后台配音系统,这是后台语音合成示例。',
|
||||
text_lang: 'zh',
|
||||
ref_audio_path: computed(() => currentCharacter.value?.refAudioPath || '').value, // 初始化时取默认角色的路径
|
||||
aux_ref_audio_paths: [],
|
||||
prompt_text: computed(() => currentCharacter.value?.promptText || '').value, // 初始化时取默认角色的提示文本
|
||||
prompt_lang: 'zh',
|
||||
top_k: 5,
|
||||
top_p: 1.0,
|
||||
temperature: 1.0,
|
||||
text_split_method: 'cut5',
|
||||
batch_size: 1,
|
||||
batch_threshold: 0.75,
|
||||
split_bucket: true,
|
||||
speed_factor: 1.0,
|
||||
streaming_mode: true,
|
||||
seed: -1,
|
||||
parallel_infer: true,
|
||||
repetition_penalty: 1.35,
|
||||
sample_steps: 32,
|
||||
super_sampling: false,
|
||||
media_type: 'wav',
|
||||
});
|
||||
|
||||
// 表单验证规则
|
||||
const ttsRules: FormRules = {
|
||||
text: [
|
||||
{ required: true, message: '请输入待合成的文本', trigger: 'blur' },
|
||||
],
|
||||
text_lang: [
|
||||
{ required: true, message: '请选择文本语言', trigger: 'change' },
|
||||
],
|
||||
prompt_lang: [
|
||||
{ required: true, message: '请选择提示文本语言', trigger: 'change' },
|
||||
],
|
||||
};
|
||||
|
||||
// 模型切换状态
|
||||
const modelSwitching = reactive({
|
||||
gpt: false,
|
||||
sovits: false,
|
||||
});
|
||||
|
||||
const ttsFormRef = ref<FormInstance>();
|
||||
const isGenerating = ref(false);
|
||||
const audioUrl = ref<string | null>(null); // 初始值设为 null
|
||||
const log = ref('');
|
||||
|
||||
// 切换模型辅助函数
|
||||
const switchGPTModel = async (path: string) => {
|
||||
try {
|
||||
const response = await fetch(`${apiConfig.baseUrl}/set_gpt_weights?weights_path=${encodeURIComponent(path)}`, {
|
||||
method: 'GET',
|
||||
});
|
||||
const responseText = await response.text(); // 读取响应文本
|
||||
if(response.status === 200) {
|
||||
log.value += 'GPT 模型切换成功!\n';
|
||||
ElMessage.success('GPT 模型切换成功');
|
||||
return true;
|
||||
} else {
|
||||
log.value += `GPT 模型切换失败: ${responseText}\n`;
|
||||
ElMessage.error(`GPT 模型切换失败: ${responseText}`);
|
||||
return false;
|
||||
}
|
||||
} catch (error: any) {
|
||||
log.value += `GPT 模型切换网络错误: ${error.message}\n`;
|
||||
ElMessage.error(`GPT 模型切换网络错误: ${error.message}`);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
const switchSoVITSModel = async (path: string) => {
|
||||
try {
|
||||
const response = await fetch(`${apiConfig.baseUrl}/set_sovits_weights?weights_path=${encodeURIComponent(path)}`, {
|
||||
method: 'GET',
|
||||
});
|
||||
const responseText = await response.text(); // 读取响应文本
|
||||
if(response.status === 200) {
|
||||
log.value += 'SoVITS 模型切换成功!\n';
|
||||
ElMessage.success('SoVITS 模型切换成功');
|
||||
return true;
|
||||
} else {
|
||||
log.value += `SoVITS 模型切换失败: ${responseText}\n`;
|
||||
ElMessage.error(`SoVITS 模型切换失败: ${responseText}`);
|
||||
return false;
|
||||
}
|
||||
} catch (error: any) {
|
||||
log.value += `SoVITS 模型切换网络错误: ${error.message}\n`;
|
||||
ElMessage.error(`SoVITS 模型切换网络错误: ${error.message}`);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// 根据选中的角色切换模型
|
||||
const switchModelByCharacter = async (characterId: string) => {
|
||||
const char = currentCharacter.value;
|
||||
if (!char) {
|
||||
ElMessage.error(`找不到角色 ID "${characterId}" 的配置。`);
|
||||
log.value += `错误: 找不到角色 ID "${characterId}" 的配置。\n`;
|
||||
return;
|
||||
}
|
||||
|
||||
// 更新 ttsParams 中由角色决定的字段
|
||||
ttsParams.ref_audio_path = char.refAudioPath;
|
||||
ttsParams.prompt_text = char.promptText || '';
|
||||
|
||||
log.value += `开始切换模型为角色 "${char.name}"...\n`;
|
||||
|
||||
// 1. 切换 GPT 模型
|
||||
modelSwitching.gpt = true;
|
||||
log.value += `正在切换 GPT 模型到: ${char.gptPath}\n`;
|
||||
const gptSuccess = await switchGPTModel(char.gptPath);
|
||||
modelSwitching.gpt = false;
|
||||
|
||||
// 2. 切换 SoVITS 模型
|
||||
modelSwitching.sovits = true;
|
||||
log.value += `正在切换 SoVITS 模型到: ${char.sovitsPath}\n`;
|
||||
const sovitsSuccess = await switchSoVITSModel(char.sovitsPath);
|
||||
modelSwitching.sovits = false;
|
||||
|
||||
if (gptSuccess && sovitsSuccess) {
|
||||
log.value += `角色 "${char.name}" 的模型切换完成!\n`;
|
||||
} else {
|
||||
log.value += `角色 "${char.name}" 的模型切换部分失败或全部失败。\n`;
|
||||
}
|
||||
};
|
||||
|
||||
// 合成语音
|
||||
const synthesize = async () => {
|
||||
const validate = await ttsFormRef.value?.validate().catch(() => false);
|
||||
if (!validate) {
|
||||
ElMessage.error('请检查输入参数');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!currentCharacter.value) {
|
||||
ElMessage.error('当前角色配置无效,请重新选择。');
|
||||
return;
|
||||
}
|
||||
|
||||
isGenerating.value = true;
|
||||
log.value += '开始合成语音...\n';
|
||||
clearAudio(); // 清空之前的音频
|
||||
|
||||
try {
|
||||
// 构建 POST 请求体
|
||||
const requestBody = { ...ttsParams };
|
||||
// 如果 prompt_text 为空,则从 payload 中移除
|
||||
if (!requestBody.prompt_text) {
|
||||
delete requestBody.prompt_text;
|
||||
}
|
||||
|
||||
const response = await fetch(`${apiConfig.baseUrl}/tts`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(requestBody),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({ message: `HTTP Error ${response.status}` }));
|
||||
throw new Error(errorData.message || `HTTP Error ${response.status}`);
|
||||
}
|
||||
|
||||
// 检查返回的是否为音频流
|
||||
const contentType = response.headers.get('content-type');
|
||||
if (!contentType || !contentType.includes('audio')) {
|
||||
const errorText = await response.text();
|
||||
throw new Error(`API returned non-audio content: ${errorText}`);
|
||||
}
|
||||
|
||||
const audioBlob = await response.blob();
|
||||
// 创建临时 URL 用于播放和下载
|
||||
const newUrl = URL.createObjectURL(audioBlob);
|
||||
audioUrl.value = newUrl;
|
||||
log.value += '语音合成成功!\n';
|
||||
ElMessage.success('语音合成成功');
|
||||
} catch (error: any) {
|
||||
console.error('Synthesis failed:', error);
|
||||
log.value += `语音合成失败: ${error.message}\n`;
|
||||
ElMessage.error(`语音合成失败: ${error.message}`);
|
||||
} finally {
|
||||
isGenerating.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 停止生成 (当前 fetch 无法真正中断,主要重置 UI 状态)
|
||||
const stopGeneration = () => {
|
||||
isGenerating.value = false;
|
||||
log.value += '用户已请求停止生成。\n';
|
||||
ElMessage.info('已请求停止生成');
|
||||
};
|
||||
|
||||
// 清空音频
|
||||
const clearAudio = () => {
|
||||
if (audioUrl.value) {
|
||||
URL.revokeObjectURL(audioUrl.value);
|
||||
audioUrl.value = null;
|
||||
}
|
||||
};
|
||||
|
||||
// 组件卸载时清理 URL 对象
|
||||
onUnmounted(() => {
|
||||
clearAudio();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tts-app {
|
||||
padding: 20px;
|
||||
max-width: 1000px;
|
||||
margin: 0 auto;
|
||||
|
||||
.box-card {
|
||||
min-width: 800px;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.config-section,
|
||||
.character-section,
|
||||
.params-section,
|
||||
.controls-section,
|
||||
.audio-section,
|
||||
.log-section {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.controls-section {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.audio-player {
|
||||
width: 100%;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.log-content {
|
||||
background-color: #f5f5f5;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
padding: 10px;
|
||||
height: 150px;
|
||||
overflow-y: auto;
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,142 @@
|
||||
<template>
|
||||
<el-dialog v-model="visible" :title="!dataForm.id ? '新增' : '修改'" :close-on-click-modal="false" :close-on-press-escape="false">
|
||||
<el-form :model="dataForm" :rules="rules" ref="dataFormRef" @keyup.enter="dataFormSubmitHandle()" label-width="120px">
|
||||
<el-form-item label=" 提供商" prop="provider">
|
||||
<el-input v-model="dataForm.provider" placeholder=" 提供商:阿里/腾讯/网易/百度/"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="名称" prop="name">
|
||||
<el-input v-model="dataForm.name" placeholder="名称"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="dataForm.remark" placeholder="备注"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="续费方式" prop="renewalType">
|
||||
<el-select v-model="dataForm.renewalType" placeholder="请选择续费方式" style="width: 240px">
|
||||
<el-option v-for="item in renewalType" :key="item.dictValue" :label="item.dictLabel" :value="item.dictValue" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="续费日" prop="renewalDate">
|
||||
<el-input-number v-model="dataForm.renewalDate" :min="1" :max="29" placeholder="具体续费日期 (1-29)" style="width: 100%" />
|
||||
</el-form-item>
|
||||
<el-form-item label="到期时间" prop="expireTime">
|
||||
<el-date-picker v-model="dataForm.expireTime" type="datetime" placeholder="选择到期时间" format="YYYY-MM-DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss" style="width: 100%" />
|
||||
</el-form-item>
|
||||
<el-form-item label="其他信息" prop="otherInfo">
|
||||
<el-input v-model="dataForm.otherInfo" placeholder="其他信息json形式"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="visible = false">取消</el-button>
|
||||
<el-button type="primary" @click="dataFormSubmitHandle()">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref, computed } from "vue";
|
||||
import baseService from "@/service/baseService";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { useAppStore } from "@/store";
|
||||
import { getDictDataList } from "@/utils/utils";
|
||||
|
||||
const store = useAppStore();
|
||||
const renewalType = getDictDataList(store.state.dicts, "renewal_type");
|
||||
|
||||
const emit = defineEmits(["refreshDataList"]);
|
||||
|
||||
const visible = ref(false);
|
||||
const dataFormRef = ref();
|
||||
|
||||
const dataForm = reactive({
|
||||
id: "",
|
||||
provider: "",
|
||||
name: "",
|
||||
remark: "",
|
||||
otherInfo: "",
|
||||
renewalType: "",
|
||||
renewalDate: null as number | null,
|
||||
expireTime: "",
|
||||
|
||||
createDate: "",
|
||||
createUser: "",
|
||||
updateDate: "",
|
||||
updateUser: ""
|
||||
});
|
||||
|
||||
const getRules = () => ({
|
||||
provider: [{ required: true, message: "必填项不能为空", trigger: "blur" }],
|
||||
name: [{ required: true, message: "必填项不能为空", trigger: "blur" }],
|
||||
remark: [{ required: true, message: "必填项不能为空", trigger: "blur" }],
|
||||
renewalType: [{ required: true, message: "必填项不能为空", trigger: "blur" }],
|
||||
renewalDate:
|
||||
dataForm.renewalType !== "1"
|
||||
? [
|
||||
{ required: true, message: "续费日不能为空", trigger: "blur" },
|
||||
{ type: "number", min: 1, max: 29, message: "日期必须在1到29之间", trigger: "blur" }
|
||||
]
|
||||
: [{ type: "number", min: 1, max: 29, message: "日期必须在1到29之间", trigger: "blur" }],
|
||||
expireTime: [{ required: true, message: "到期时间不能为空", trigger: "blur" }]
|
||||
});
|
||||
|
||||
// 使用 computed 属性,使其响应式
|
||||
const rules = computed(() => getRules());
|
||||
|
||||
const init = (id?: number) => {
|
||||
visible.value = true;
|
||||
dataForm.id = "";
|
||||
|
||||
// 重置表单数据
|
||||
if (dataFormRef.value) {
|
||||
dataFormRef.value.resetFields();
|
||||
}
|
||||
|
||||
if (id) {
|
||||
getInfo(id);
|
||||
}
|
||||
};
|
||||
|
||||
// 获取信息
|
||||
const getInfo = (id: number) => {
|
||||
baseService.get("/baitutools/dlrenewalremind/" + id).then((res) => {
|
||||
const { data } = res; // 解构出 data 对象
|
||||
|
||||
// --- 新增处理逻辑 ---
|
||||
if (data.hasOwnProperty("renewalDate")) {
|
||||
if (typeof data.renewalDate === "string") {
|
||||
const parsed = parseInt(data.renewalDate, 10);
|
||||
data.renewalDate = isNaN(parsed) ? null : parsed;
|
||||
} else if (typeof data.renewalDate === "number") {
|
||||
data.renewalDate = data.renewalDate
|
||||
} else {
|
||||
data.renewalDate = null;
|
||||
}
|
||||
}
|
||||
|
||||
// 将处理后的 data 对象合并到 dataForm
|
||||
Object.assign(dataForm, data);
|
||||
});
|
||||
};
|
||||
|
||||
// 表单提交
|
||||
const dataFormSubmitHandle = () => {
|
||||
dataFormRef.value.validate((valid: boolean) => {
|
||||
if (!valid) {
|
||||
return false;
|
||||
}
|
||||
(!dataForm.id ? baseService.post : baseService.put)("/baitutools/dlrenewalremind", dataForm).then((res) => {
|
||||
ElMessage.success({
|
||||
message: "成功",
|
||||
duration: 500,
|
||||
onClose: () => {
|
||||
visible.value = false;
|
||||
emit("refreshDataList");
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
init
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,63 @@
|
||||
<template>
|
||||
<div class="mod-baitutools__dlrenewalremind">
|
||||
<el-form :inline="true" :model="state.dataForm" @keyup.enter="state.getDataList()">
|
||||
<el-form-item>
|
||||
<el-input v-model="state.dataForm.keywordName" placeholder="名称" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button @click="state.getDataList()">查询</el-button>
|
||||
</el-form-item>
|
||||
|
||||
|
||||
<el-form-item>
|
||||
<el-button v-if="state.hasPermission('baitutools:dlrenewalremind:save')" type="primary" @click="addOrUpdateHandle()">新增</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button v-if="state.hasPermission('baitutools:dlrenewalremind:delete')" type="danger" @click="state.deleteHandle()">删除</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-table v-loading="state.dataListLoading" :data="state.dataList" border @selection-change="state.dataListSelectionChangeHandle" style="width: 100%">
|
||||
<el-table-column type="selection" header-align="center" align="center" width="50"></el-table-column>
|
||||
<el-table-column prop="provider" label=" 提供商" header-align="center" align="center"></el-table-column>
|
||||
<el-table-column prop="name" label="名称" header-align="center" align="center"></el-table-column>
|
||||
<el-table-column prop="remark" label="备注" header-align="center" align="center"></el-table-column>
|
||||
<el-table-column prop="otherInfo" label="其他信息" header-align="center" align="center"></el-table-column>
|
||||
<el-table-column prop="renewalType" label="续费方式" header-align="center" align="center"></el-table-column>
|
||||
<el-table-column prop="renewalDate" label="具体续费日期" width="130" header-align="center" align="center"></el-table-column>
|
||||
<el-table-column prop="expireTime" label="到期时间" header-align="center" align="center"></el-table-column>
|
||||
<el-table-column label="操作" fixed="right" header-align="center" align="center" width="150">
|
||||
<template v-slot="scope">
|
||||
<el-button v-if="state.hasPermission('baitutools:dlrenewalremind:update')" type="primary" link @click="addOrUpdateHandle(scope.row.id)">修改</el-button>
|
||||
<el-button v-if="state.hasPermission('baitutools:dlrenewalremind:delete')" type="primary" link @click="state.deleteHandle(scope.row.id)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination :current-page="state.page" :page-sizes="[10, 20, 50, 100]" :page-size="state.limit" :total="state.total" layout="total, sizes, prev, pager, next, jumper" @size-change="state.pageSizeChangeHandle" @current-change="state.pageCurrentChangeHandle"> </el-pagination>
|
||||
<!-- 弹窗, 新增 / 修改 -->
|
||||
<add-or-update ref="addOrUpdateRef" @refreshDataList="state.getDataList">确定</add-or-update>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import useView from "@/hooks/useView";
|
||||
import { reactive, ref, toRefs } from "vue";
|
||||
import AddOrUpdate from "./renewalremind-add-or-update.vue";
|
||||
|
||||
const view = reactive({
|
||||
deleteIsBatch: true,
|
||||
getDataListURL: "/baitutools/dlrenewalremind/page",
|
||||
getDataListIsPage: true,
|
||||
exportURL: "/baitutools/dlrenewalremind/export",
|
||||
deleteURL: "/baitutools/dlrenewalremind",
|
||||
dataForm: {
|
||||
keywordName: "",
|
||||
}
|
||||
});
|
||||
|
||||
const state = reactive({ ...useView(view), ...toRefs(view) });
|
||||
|
||||
const addOrUpdateRef = ref();
|
||||
const addOrUpdateHandle = (id?: number) => {
|
||||
addOrUpdateRef.value.init(id);
|
||||
};
|
||||
</script>
|
||||
Reference in New Issue
Block a user