初步实现,会员临期提醒功能,待完善

This commit is contained in:
DelLevin-Home
2026-02-04 23:24:49 +08:00
parent 8d11263e37
commit 9faa180627
31 changed files with 695 additions and 523 deletions

View File

@@ -3,15 +3,9 @@
- 采用SpringBoot3.x、Shiro、MyBatis-Plus、Vue3、TypeScript、Element Plus、Vue Router、Pinia、Axios、Vite框架开发的一套权限系统极低门槛拿来即用。设计之初就非常注重安全性为企业系统保驾护航让一切都变得如此简单。 - 采用SpringBoot3.x、Shiro、MyBatis-Plus、Vue3、TypeScript、Element Plus、Vue Router、Pinia、Axios、Vite框架开发的一套权限系统极低门槛拿来即用。设计之初就非常注重安全性为企业系统保驾护航让一切都变得如此简单。
- 提供了代码生成器只需编写30%左右代码,其余的代码交给系统自动生成,可快速完成开发任务 - 提供了代码生成器只需编写30%左右代码,其余的代码交给系统自动生成,可快速完成开发任务
- 支持MySQL、达梦、Oracle、SQL Server、PostgreSQL等主流数据库 - 支持MySQL、达梦、Oracle、SQL Server、PostgreSQL等主流数据库
- 演示地址http://demo.open.renren.io/renren-security 账号密码admin/admin
<br> <br>
### 微信交流群
我们提供了微信交流群,扫码下面的二维码,关注【人人开源】公众号,回复【加群】,即可根据提示加入微信群!
<br><br>
![输入图片说明](renren-admin/src/main/resources/public/wechat.jpg)
<br> <br>
### 具有如下特点 ### 具有如下特点
@@ -108,19 +102,3 @@ renren-security
- 账号密码admin/admin - 账号密码admin/admin
<br> <br>
![输入图片说明](renren-admin/src/main/resources/public/1.png)
<br>
![输入图片说明](renren-admin/src/main/resources/public/2.png)
<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>

View File

@@ -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);
}
}

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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> {
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -42,8 +42,9 @@ spring:
stat-view-servlet: stat-view-servlet:
enabled: true enabled: true
url-pattern: /druid/* url-pattern: /druid/*
#login-username: admin allow: ""
#login-password: admin # login-username: admin
# login-password: admin
#达梦数据库,需要注释掉,其他数据库可以打开 #达梦数据库,需要注释掉,其他数据库可以打开
# filter: # filter:
# stat: # stat:

View File

@@ -24,7 +24,7 @@ knife4j:
spring: spring:
# 环境 dev|test|prod # 环境 dev|test|prod
profiles: profiles:
active: prod active: dev
messages: messages:
encoding: UTF-8 encoding: UTF-8
basename: i18n/messages basename: i18n/messages
@@ -60,7 +60,7 @@ renren:
mybatis-plus: mybatis-plus:
mapper-locations: classpath*:/mapper/**/*.xml mapper-locations: classpath*:/mapper/**/*.xml
#实体扫描多个package用逗号或者分号分隔 #实体扫描多个package用逗号或者分号分隔
typeAliasesPackage: io.renren.modules.*.entity typeAliasesPackage: top.iletter.modules.*.entity
global-config: global-config:
#数据库相关配置 #数据库相关配置
db-config: db-config:

View File

@@ -8,14 +8,14 @@
<springProfile name="dev,test"> <springProfile name="dev,test">
<logger name="org.springframework.web" level="INFO"/> <logger name="org.springframework.web" level="INFO"/>
<logger name="org.springboot.sample" level="INFO" /> <logger name="org.springboot.sample" level="INFO" />
<logger name="io.renren" level="DEBUG" /> <logger name="top.iletter" level="DEBUG" />
</springProfile> </springProfile>
<!-- 生产环境 --> <!-- 生产环境 -->
<springProfile name="prod"> <springProfile name="prod">
<logger name="org.springframework.web" level="ERROR"/> <logger name="org.springframework.web" level="ERROR"/>
<logger name="org.springboot.sample" level="ERROR" /> <logger name="org.springboot.sample" level="ERROR" />
<logger name="io.renren" level="ERROR" /> <logger name="top.iletter" level="ERROR" />
</springProfile> </springProfile>
</configuration> </configuration>

View File

@@ -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

View File

@@ -8,14 +8,14 @@
<springProfile name="dev,test"> <springProfile name="dev,test">
<logger name="org.springframework.web" level="INFO"/> <logger name="org.springframework.web" level="INFO"/>
<logger name="org.springboot.sample" level="INFO" /> <logger name="org.springboot.sample" level="INFO" />
<logger name="io.renren" level="DEBUG" /> <logger name="top.iletter" level="DEBUG" />
</springProfile> </springProfile>
<!-- 生产环境 --> <!-- 生产环境 -->
<springProfile name="prod"> <springProfile name="prod">
<logger name="org.springframework.web" level="ERROR"/> <logger name="org.springframework.web" level="ERROR"/>
<logger name="org.springboot.sample" level="ERROR" /> <logger name="org.springboot.sample" level="ERROR" />
<logger name="io.renren" level="ERROR" /> <logger name="top.iletter" level="ERROR" />
</springProfile> </springProfile>
</configuration> </configuration>

View File

@@ -53,7 +53,7 @@ public class SysGeneratorController {
byte[] data = sysGeneratorService.generatorCode(tables.split(",")); byte[] data = sysGeneratorService.generatorCode(tables.split(","));
response.reset(); 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.addHeader("Content-Length", "" + data.length);
response.setContentType("application/octet-stream; charset=UTF-8"); response.setContentType("application/octet-stream; charset=UTF-8");

View File

@@ -1,18 +1,17 @@
#\u4EE3\u7801\u751F\u6210\u5668\uFF0C\u914D\u7F6E\u4FE1\u606F #\u4EE3\u7801\u751F\u6210\u5668\uFF0C\u914D\u7F6E\u4FE1\u606F
#\u5305\u540D
package=io.renren package=top.iletter
moduleName=demo moduleName=baitutools
#\u4F5C\u8005 author=dellevin
author=Mark
#Email #Email
email=sunlightcs@gmail.com email=dellevin99@gmail.com
#\u8868\u524D\u7F00(\u7C7B\u540D\u4E0D\u4F1A\u5305\u542B\u8868\u524D\u7F00) #???(?????????)
tablePrefix=tb_ tablePrefix=tb_
version=1.0.0 version=1.0.0
#\u7C7B\u578B\u8F6C\u6362\uFF0C\u914D\u7F6E\u4FE1\u606F # ?????????
tinyint=Integer tinyint=Integer
smallint=Integer smallint=Integer
mediumint=Integer mediumint=Integer

View File

@@ -6,6 +6,6 @@
<logger name="org.springframework.web" level="INFO"/> <logger name="org.springframework.web" level="INFO"/>
<logger name="org.springboot.sample" level="INFO" /> <logger name="org.springboot.sample" level="INFO" />
<logger name="io.renren" level="DEBUG" /> <logger name="top.iletter" level="DEBUG" />
</configuration> </configuration>

View File

@@ -3,7 +3,7 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>人人代码生成器</title> <title>代码生成器</title>
<!-- Tell the browser to be responsive to screen width --> <!-- 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"> <meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
<link rel="stylesheet" href="css/bootstrap.min.css"> <link rel="stylesheet" href="css/bootstrap.min.css">
@@ -27,9 +27,9 @@
<header class="main-header"> <header class="main-header">
<a href="javascript:void(0);" class="logo"> <a href="javascript:void(0);" class="logo">
<!-- mini logo for sidebar mini 50x50 pixels --> <!-- 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 --> <!-- logo for regular state and mobile devices -->
<span class="logo-lg"><b>人人代码生成器</b></span> <span class="logo-lg"><b>代码生成器</b></span>
</a> </a>
<!-- Header Navbar: style can be found in header.less --> <!-- Header Navbar: style can be found in header.less -->
<nav class="navbar navbar-static-top" role="navigation"> <nav class="navbar navbar-static-top" role="navigation">
@@ -40,8 +40,7 @@
<div style="float:left;color:#fff;padding:15px 10px;">代码的搬运工</div> <div style="float:left;color:#fff;padding:15px 10px;">代码的搬运工</div>
<div class="navbar-custom-menu"> <div class="navbar-custom-menu">
<ul class="nav navbar-nav"> <ul class="nav navbar-nav">
<li><a href="javascript:;" @click="donate"><i class="fa fa-jpy"></i> &nbsp;捐赠作者</a></li>
<li><a href="https://www.renren.io" target="_blank"><i class="fa fa-home"></i> &nbsp;人人开源</a></li>
</ul> </ul>
</div> </div>
</nav> </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> <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;"> <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 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> </ul>
</li> </li>
</ul> </ul>

View File

@@ -11,18 +11,7 @@
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading">基本信息</div> <div class="panel-heading">基本信息</div>
<div style="padding: 10px 0 20px 10px;"> <div style="padding: 10px 0 20px 10px;">
<h3>&nbsp;&nbsp;&nbsp;获取帮助</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>
</div> </div>
</body> </body>

View File

@@ -1,3 +1,3 @@
NODE_ENV=development NODE_ENV=development
VITE_APP_API=http://152.136.153.72:27005/admin # VITE_APP_API=http://152.136.153.72:27005/admin
# VITE_APP_API=http://10.8.0.3/api/admin VITE_APP_API=http://10.8.0.3:8888/admin

View File

@@ -21,28 +21,3 @@ npm install
# 启动项目 # 启动项目
npm run dev 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>

View File

@@ -28,7 +28,7 @@ export default defineComponent({
<span :class="`rr-header-ctx-logo-img-wrap ${'enabled-logo-' + app.enabledLogo}`"> <span :class="`rr-header-ctx-logo-img-wrap ${'enabled-logo-' + app.enabledLogo}`">
<!-- 支持显示图片logo或者产品名称缩写二选一模式通过注释开启功能app.enabledLogo控制正常模式下图片logo是否显示如果有图片logo收起状态会强制显示图片logo --> <!-- 支持显示图片logo或者产品名称缩写二选一模式通过注释开启功能app.enabledLogo控制正常模式下图片logo是否显示如果有图片logo收起状态会强制显示图片logo -->
<!-- <img :src="props.logoUrl" class="rr-header-ctx-logo-img" :alt="props.logoName" /> --> <!-- <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 class="rr-header-ctx-logo-line"></span>
</span> </span>
<span class="rr-header-ctx-logo-text">{{ props.logoName }}</span> <span class="rr-header-ctx-logo-text">{{ props.logoName }}</span>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -13,6 +13,8 @@ git remote add origin https://gitea.iletter.top/dellevin/my_sys.git
git branch git branch
# 推送 push -u 简短别名 本地分支名称:远程分支名称 --force # 推送 push -u 简短别名 本地分支名称:远程分支名称 --force
git push -u origin master:main --force git push -u origin master:main --force
# 推送
git push origin master:main
``` ```
## npm运行 ## npm运行