This commit is contained in:
ls
2024-11-05 20:40:45 +08:00
parent 639d0ee799
commit 255af5b1a8
45 changed files with 161 additions and 3434 deletions

View File

@@ -182,10 +182,10 @@
<!-- Quartz定时任务 --> <!-- Quartz定时任务 -->
<dependency> <!-- <dependency>-->
<groupId>org.springframework.boot</groupId> <!-- <groupId>org.springframework.boot</groupId>-->
<artifactId>spring-boot-starter-quartz</artifactId> <!-- <artifactId>spring-boot-starter-quartz</artifactId>-->
</dependency> <!-- </dependency>-->
<!--JWT--> <!--JWT-->
<dependency> <dependency>

View File

@@ -1,76 +0,0 @@
package org.jeecg.test.sqlinjection;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.JSQLParserException;
import org.jeecg.common.util.SqlInjectionUtil;
import org.junit.Test;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
/**
* SQL注入攻击检查测试
*
* @author: liusq
* @date: 2023年09月08日
*/
@Slf4j
public class TestInjectWithSqlParser {
/**
* 注入测试
*
* @param sql
* @return
*/
private boolean isExistSqlInject(String sql) {
try {
SqlInjectionUtil.specialFilterContentForOnlineReport(sql);
return false;
} catch (Exception e) {
log.info("===================================================");
return true;
}
}
@Test
public void test() throws JSQLParserException {
//不存在sql注入
assertFalse(isExistSqlInject("select * from fm_time where dept_id=:sqlparamsmap.id and time=:sqlparamsmap.time"));
assertFalse(isExistSqlInject("select * from test"));
assertFalse(isExistSqlInject("select load_file(\"C:\\\\benben.txt\")"));
assertFalse(isExistSqlInject("WITH SUB1 AS (SELECT user FROM t1) SELECT * FROM T2 WHERE id > 123 "));
//存在sql注入
assertTrue(isExistSqlInject("or 1= 1 --"));
assertTrue(isExistSqlInject("select * from test where sleep(%23)"));
assertTrue(isExistSqlInject("select * from test where id=1 and multipoint((select * from(select * from(select user())a)b));"));
assertTrue(isExistSqlInject("select * from users;show databases;"));
assertTrue(isExistSqlInject("select * from dc_device where id=1 and length((select group_concat(table_name) from information_schema.tables where table_schema=database()))>13"));
assertTrue(isExistSqlInject("update user set name = '123'"));
assertTrue(isExistSqlInject("SELECT * FROM users WHERE username = 'admin' AND password = '123456' OR 1=1;--"));
assertTrue(isExistSqlInject("select * from users where id=1 and (select count(*) from information_schema.tables where table_schema='数据库名')>4 %23"));
assertTrue(isExistSqlInject("select * from dc_device where sleep(5) %23"));
assertTrue(isExistSqlInject("select * from dc_device where id in (select id from other)"));
assertTrue(isExistSqlInject("select * from dc_device where id in (select id from other)"));
assertTrue(isExistSqlInject("select * from dc_device where 2=2.0 or 2 != 4"));
assertTrue(isExistSqlInject("select * from dc_device where 1!=2.0"));
assertTrue(isExistSqlInject("select * from dc_device where id=floor(2.0)"));
assertTrue(isExistSqlInject("select * from dc_device where not true"));
assertTrue(isExistSqlInject("select * from dc_device where 1 or id > 0"));
assertTrue(isExistSqlInject("select * from dc_device where 'tom' or id > 0"));
assertTrue(isExistSqlInject("select * from dc_device where '-2.3' "));
assertTrue(isExistSqlInject("select * from dc_device where 2 "));
assertTrue(isExistSqlInject("select * from dc_device where (3+2) "));
assertTrue(isExistSqlInject("select * from dc_device where -1 IS TRUE"));
assertTrue(isExistSqlInject("select * from dc_device where 'hello' is null "));
assertTrue(isExistSqlInject("select * from dc_device where '2022-10-31' and id > 0"));
assertTrue(isExistSqlInject("select * from dc_device where id > 0 or 1!=2.0 "));
assertTrue(isExistSqlInject("select * from dc_device where id > 0 or 1 in (1,3,4) "));
assertTrue(isExistSqlInject("select * from dc_device UNION select name from other"));
assertTrue(isExistSqlInject("(SELECT 6240 FROM (SELECT(SLEEP(5))and 1=2)vidl)"));
}
}

View File

@@ -1,51 +0,0 @@
package org.jeecg.test.sqlinjection;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.JSQLParserException;
import org.jeecg.common.util.SqlInjectionUtil;
import org.junit.Test;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
/**
* SQL注入攻击检查测试
*
* @author: liusq
* @date: 2023年09月08日
*/
@Slf4j
public class TestSqlInjectForDict {
/**
* 注入测试
*
* @param sql
* @return
*/
private boolean isExistSqlInject(String sql) {
try {
SqlInjectionUtil.specialFilterContentForDictSql(sql);
return false;
} catch (Exception e) {
log.info("===================================================");
return true;
}
}
@Test
public void test() throws JSQLParserException {
//不存在sql注入
assertFalse(isExistSqlInject("sys_user,realname,id"));
assertFalse(isExistSqlInject("oa_officialdoc_organcode,organ_name,id"));
assertFalse(isExistSqlInject("onl_cgform_head where table_type!=3 and copy_type=0,table_txt,table_name"));
assertFalse(isExistSqlInject("onl_cgform_head where copy_type = 0,table_txt,table_name"));
//存在sql注入
assertTrue(isExistSqlInject("or 1= 1 --"));
assertTrue(isExistSqlInject("select * from test where sleep(%23)"));
}
}

View File

@@ -1,61 +0,0 @@
package org.jeecg.test.sqlinjection;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.JSQLParserException;
import org.jeecg.common.util.SqlInjectionUtil;
import org.junit.Test;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
/**
* SQL注入攻击检查测试
*
* @author: liusq
* @date: 2023年09月08日
*/
@Slf4j
public class TestSqlInjectForOnlineReport {
/**
* 注入测试
*
* @param sql
* @return
*/
private boolean isExistSqlInject(String sql) {
try {
SqlInjectionUtil.specialFilterContentForOnlineReport(sql);
return false;
} catch (Exception e) {
log.info("===================================================");
return true;
}
}
@Test
public void test() throws JSQLParserException {
//不存在sql注入
assertFalse(isExistSqlInject("select * from fm_time where dept_id=:sqlparamsmap.id and time=:sqlparamsmap.time"));
assertFalse(isExistSqlInject("select * from test"));
assertFalse(isExistSqlInject("select load_file(\"C:\\\\benben.txt\")"));
assertFalse(isExistSqlInject("select * from dc_device where id in (select id from other)"));
assertFalse(isExistSqlInject("select * from dc_device UNION select name from other"));
//存在sql注入
assertTrue(isExistSqlInject("(SELECT 6240 FROM (SELECT(SLEEP(5))and 1=2)vidl)"));
assertTrue(isExistSqlInject("or 1= 1 --"));
assertTrue(isExistSqlInject("select * from test where sleep(%23)"));
assertTrue(isExistSqlInject("select * from test where SLEEP(3)"));
assertTrue(isExistSqlInject("select * from test where id=1 and multipoint((select * from(select * from(select user())a)b));"));
assertTrue(isExistSqlInject("select * from users;show databases;"));
assertTrue(isExistSqlInject("select * from dc_device where id=1 and length((select group_concat(table_name) from information_schema.tables where table_schema=database()))>13"));
assertTrue(isExistSqlInject("update user set name = '123'"));
assertTrue(isExistSqlInject("SELECT * FROM users WHERE username = 'admin' AND password = '123456' OR 1=1;--"));
assertTrue(isExistSqlInject("select * from users where id=1 and (select count(*) from information_schema.tables where table_schema='数据库名')>4 %23"));
assertTrue(isExistSqlInject("select * from dc_device where sleep(5) %23"));
}
}

View File

@@ -1,103 +0,0 @@
package org.jeecg.test.sqlinjection;
import com.baomidou.mybatisplus.core.toolkit.sql.SqlInjectionUtils;
import org.jeecg.common.util.SqlInjectionUtil;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
/**
* @Description: SQL注入测试类
* @author: scott
* @date: 2023年08月14日 9:55
*/
public class TestSqlInjection {
/**
* 表名带别名同时有html编码字符
*/
@Test
public void testSpecialSQL() {
String tableName = "sys_user t";
//解决使用参数tableName=sys_user t&复测,漏洞仍然存在
if (tableName.contains(" ")) {
tableName = tableName.substring(0, tableName.indexOf(" "));
}
//【issues/4393】 sys_user , (sys_user), sys_user%20, %60sys_user%60
String reg = "\\s+|\\(|\\)|`";
tableName = tableName.replaceAll(reg, "");
System.out.println(tableName);
}
/**
* 测试sql是否含sql注入风险
* <p>
* mybatis plus的方法
*/
@Test
public void sqlInjectionCheck() {
String sql = "select * from sys_user";
System.out.println(SqlInjectionUtils.check(sql));
}
/**
* 测试sql是否有SLEEP风险
* <p>
* mybatisPlus的方法
*/
@Test
public void sqlSleepCheck() {
SqlInjectionUtil.checkSqlAnnotation("(SELECT 6240 FROM (SELECT(SLEEP(5))and 1=2)vidl)");
}
/**
* 测试sql是否含sql注入风险
* <p>
* 自定义方法
*/
@Test
public void sqlInjectionCheck2() {
String sql = "select * from sys_user";
SqlInjectionUtil.specialFilterContentForOnlineReport(sql);
}
/**
* 字段定义只能是是字母 数字 下划线的组合(不允许有空格、转义字符串等)
* <p>
* 判断字段名是否符合规范
*/
@Test
public void testFieldSpecification() {
List<String> list = new ArrayList();
list.add("Hello World!");
list.add("Hello%20World!");
list.add("HelloWorld!");
list.add("Hello World");
list.add("age");
list.add("user_name");
list.add("user_name%20");
list.add("user_name%20 ");
for (String input : list) {
boolean containsSpecialChars = isValidString(input);
System.out.println("input:" + input + " ,包含空格和特殊字符: " + containsSpecialChars);
}
}
/**
* 字段定义只能是是字母 数字 下划线的组合(不允许有空格、转义字符串等)
*
* @param input
* @return
*/
private static boolean isValidString(String input) {
Pattern pattern = Pattern.compile("^[a-zA-Z0-9_]+$");
return pattern.matcher(input).matches();
}
}

View File

@@ -1,109 +0,0 @@
package org.jeecg.test.sqlparse;
import net.sf.jsqlparser.JSQLParserException;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.common.util.sqlparse.JSqlParserUtils;
import org.jeecg.common.util.sqlparse.vo.SelectSqlInfo;
import org.junit.Test;
import java.util.Map;
/**
* 针对 JSqlParserUtils 的单元测试
*/
public class JSqlParserUtilsTest {
private static final String[] sqlList = new String[]{
"select * from sys_user",
"select u.* from sys_user u",
"select u.*, c.name from sys_user u, demo c",
"select u.age, c.name from sys_user u, demo c",
"select sex, age, c.name from sys_user, demo c",
// 别名测试
"select username as realname from sys_user",
"select username as realname, u.realname as aaa, u.id bbb from sys_user u",
// 不存在真实地查询字段
"select count(1) from sys_user",
// 函数式字段
"select max(sex), id from sys_user",
// 复杂嵌套函数式字段
"select CONCAT(CONCAT(' _ ', sex), ' - ' , birthday) as info, id from sys_user",
// 更复杂的嵌套函数式字段
"select CONCAT(CONCAT(101,'_',NULL, DATE(create_time),'_',sex),' - ',birthday) as info, id from sys_user",
// 子查询SQL
"select u.name1 as name2 from (select username as name1 from sys_user) u",
// 多层嵌套子查询SQL
"select u2.name2 as name3 from (select u1.name1 as name2 from (select username as name1 from sys_user) u1) u2",
// 字段子查询SQL
"select id, (select username as name1 from sys_user u2 where u1.id = u2.id) as name2 from sys_user u1",
// 带条件的SQL不解析where条件里的字段但不影响解析查询字段
"select username as name1 from sys_user where realname LIKE '%张%'",
// 多重复杂关联表查询解析包含的表为sys_user, sys_depart, sys_dict_item, demo
"" +
"SELECT " +
" u.*, d.age, sd.item_text AS sex, (SELECT count(sd.id) FROM sys_depart sd) AS count " +
"FROM " +
" (SELECT sd.username AS foo, sd.realname FROM sys_user sd) u, " +
" demo d " +
"LEFT JOIN sys_dict_item AS sd ON d.sex = sd.item_value " +
"WHERE sd.dict_id = '3d9a351be3436fbefb1307d4cfb49bf2'",
};
@Test
public void testParseSelectSql() {
System.out.println("-----------------------------------------");
for (String sql : sqlList) {
System.out.println("待测试的sql" + sql);
try {
// 解析所有的表名key=表名value=解析后的sql信息
Map<String, SelectSqlInfo> parsedMap = JSqlParserUtils.parseAllSelectTable(sql);
assert parsedMap != null;
for (Map.Entry<String, SelectSqlInfo> entry : parsedMap.entrySet()) {
System.out.println("表名:" + entry.getKey());
this.printSqlInfo(entry.getValue(), 1);
}
} catch (JSQLParserException e) {
System.out.println("SQL解析出现异常" + e.getMessage());
}
System.out.println("-----------------------------------------");
}
}
private void printSqlInfo(SelectSqlInfo sqlInfo, int level) {
String beforeStr = this.getBeforeStr(level);
if (sqlInfo.getFromTableName() == null) {
// 子查询
System.out.println(beforeStr + "子查询:" + sqlInfo.getFromSubSelect().getParsedSql());
this.printSqlInfo(sqlInfo.getFromSubSelect(), level + 1);
} else {
// 非子查询
System.out.println(beforeStr + "查询的表名:" + sqlInfo.getFromTableName());
}
if (oConvertUtils.isNotEmpty(sqlInfo.getFromTableAliasName())) {
System.out.println(beforeStr + "查询的表别名:" + sqlInfo.getFromTableAliasName());
}
if (sqlInfo.isSelectAll()) {
System.out.println(beforeStr + "查询的字段:*");
} else {
System.out.println(beforeStr + "查询的字段:" + sqlInfo.getSelectFields());
System.out.println(beforeStr + "真实的字段:" + sqlInfo.getRealSelectFields());
if (sqlInfo.getFromTableName() == null) {
System.out.println(beforeStr + "所有的字段(包括子查询):" + sqlInfo.getAllRealSelectFields());
}
}
}
// 打印前缀,根据层级来打印
private String getBeforeStr(int level) {
if (level == 0) {
return "";
}
StringBuilder beforeStr = new StringBuilder();
for (int i = 0; i < level; i++) {
beforeStr.append(" ");
}
beforeStr.append("- ");
return beforeStr.toString();
}
}

View File

@@ -1,36 +0,0 @@
package org.jeecg.test.sqlparse;
import org.jeecg.common.util.IpUtils;
import org.jeecg.common.util.oConvertUtils;
import org.junit.Test;
import java.util.HashMap;
import java.util.Map;
/**
* @author: scott
* @date: 2024年04月29日 16:48
*/
public class TestIpUtil {
public static void main(String[] args) {
Map<String, String[]> map = new HashMap<>();
map.put("key1", new String[]{"value1", "value2", "value3"});
map.put("key4", null);
map.put("key2", new String[]{"value4", "value5"});
map.put("key3", new String[]{"value6"});
System.out.println(oConvertUtils.mapToString(map));
}
@Test
public void test() {
String ip = "2408:8207:1851:10e0:50bd:1a50:60c8:b030, 115.231.101.180";
String[] ipAddresses = ip.split(",");
for (String ipAddress : ipAddresses) {
System.out.println(ipAddress);
ipAddress = ipAddress.trim();
if (IpUtils.isValidIpAddress(ipAddress)) {
System.out.println("ipAddress= " + ipAddress);
}
}
}
}

View File

@@ -64,33 +64,33 @@ spring:
enable: true enable: true
required: true required: true
## quartz定时任务,采用数据库方式 ## quartz定时任务,采用数据库方式
quartz: # quartz:
job-store-type: jdbc # job-store-type: jdbc
initialize-schema: embedded # initialize-schema: embedded
#定时任务启动开关true-开 false-关 # #定时任务启动开关true-开 false-关
auto-startup: true # auto-startup: true
#延迟1秒启动定时任务 # #延迟1秒启动定时任务
startup-delay: 1s # startup-delay: 1s
#启动时更新己存在的Job # #启动时更新己存在的Job
overwrite-existing-jobs: true # overwrite-existing-jobs: true
properties: # properties:
org: # org:
quartz: # quartz:
scheduler: # scheduler:
instanceName: MyScheduler # instanceName: MyScheduler
instanceId: AUTO # instanceId: AUTO
jobStore: # jobStore:
class: org.springframework.scheduling.quartz.LocalDataSourceJobStore # class: org.springframework.scheduling.quartz.LocalDataSourceJobStore
driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate # driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
tablePrefix: QRTZ_ # tablePrefix: QRTZ_
isClustered: true # isClustered: true
misfireThreshold: 12000 # misfireThreshold: 12000
clusterCheckinInterval: 15000 # clusterCheckinInterval: 15000
threadPool: # threadPool:
class: org.quartz.simpl.SimpleThreadPool # class: org.quartz.simpl.SimpleThreadPool
threadCount: 10 # threadCount: 10
threadPriority: 5 # threadPriority: 5
threadsInheritContextClassLoaderOfInitializingThread: true # threadsInheritContextClassLoaderOfInitializingThread: true
#json 时间戳统一转换 #json 时间戳统一转换
jackson: jackson:
date-format: yyyy-MM-dd HH:mm:ss date-format: yyyy-MM-dd HH:mm:ss
@@ -166,8 +166,8 @@ spring:
slow-sql-millis: 5000 slow-sql-millis: 5000
datasource: datasource:
master: master:
# url: jdbc:mysql://127.0.0.1:3306/physical-boot?characterEncoding=UTF-8&useUnicode=true&useSSL=false&tinyInt1isBit=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai url: jdbc:mysql://127.0.0.1:3306/physical-boot?characterEncoding=UTF-8&useUnicode=true&useSSL=false&tinyInt1isBit=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
url: jdbc:mysql://192.168.50.100:23306/physical-boot?characterEncoding=UTF-8&useUnicode=true&useSSL=false&tinyInt1isBit=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai # url: jdbc:mysql://192.168.50.100:23306/physical-boot?characterEncoding=UTF-8&useUnicode=true&useSSL=false&tinyInt1isBit=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
username: root username: root
password: 123456 password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver driver-class-name: com.mysql.cj.jdbc.Driver

View File

@@ -64,33 +64,33 @@ spring:
enable: true enable: true
required: true required: true
## quartz定时任务,采用数据库方式 ## quartz定时任务,采用数据库方式
quartz: # quartz:
job-store-type: jdbc # job-store-type: jdbc
initialize-schema: embedded # initialize-schema: embedded
#定时任务开关true-开 false-关 # #定时任务开关true-开 false-关
auto-startup: false # auto-startup: false
#延迟1秒启动定时任务 # #延迟1秒启动定时任务
startup-delay: 1s # startup-delay: 1s
#启动时更新己存在的Job # #启动时更新己存在的Job
overwrite-existing-jobs: true # overwrite-existing-jobs: true
properties: # properties:
org: # org:
quartz: # quartz:
scheduler: # scheduler:
instanceName: MyScheduler # instanceName: MyScheduler
instanceId: AUTO # instanceId: AUTO
jobStore: # jobStore:
class: org.springframework.scheduling.quartz.LocalDataSourceJobStore # class: org.springframework.scheduling.quartz.LocalDataSourceJobStore
driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate # driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
tablePrefix: QRTZ_ # tablePrefix: QRTZ_
isClustered: true # isClustered: true
misfireThreshold: 12000 # misfireThreshold: 12000
clusterCheckinInterval: 15000 # clusterCheckinInterval: 15000
threadPool: # threadPool:
class: org.quartz.simpl.SimpleThreadPool # class: org.quartz.simpl.SimpleThreadPool
threadCount: 10 # threadCount: 10
threadPriority: 5 # threadPriority: 5
threadsInheritContextClassLoaderOfInitializingThread: true # threadsInheritContextClassLoaderOfInitializingThread: true
#json 时间戳统一转换 #json 时间戳统一转换
jackson: jackson:
date-format: yyyy-MM-dd HH:mm:ss date-format: yyyy-MM-dd HH:mm:ss

View File

@@ -64,33 +64,33 @@ spring:
enable: true enable: true
required: true required: true
## quartz定时任务,采用数据库方式 ## quartz定时任务,采用数据库方式
quartz: # quartz:
job-store-type: jdbc # job-store-type: jdbc
initialize-schema: embedded # initialize-schema: embedded
#定时任务开关true-开 false-关 # #定时任务开关true-开 false-关
auto-startup: true # auto-startup: true
#延迟1秒启动定时任务 # #延迟1秒启动定时任务
startup-delay: 1s # startup-delay: 1s
#启动时更新己存在的Job # #启动时更新己存在的Job
overwrite-existing-jobs: true # overwrite-existing-jobs: true
properties: # properties:
org: # org:
quartz: # quartz:
scheduler: # scheduler:
instanceName: MyScheduler # instanceName: MyScheduler
instanceId: AUTO # instanceId: AUTO
jobStore: # jobStore:
class: org.springframework.scheduling.quartz.LocalDataSourceJobStore # class: org.springframework.scheduling.quartz.LocalDataSourceJobStore
driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate # driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
tablePrefix: QRTZ_ # tablePrefix: QRTZ_
isClustered: true # isClustered: true
misfireThreshold: 12000 # misfireThreshold: 12000
clusterCheckinInterval: 15000 # clusterCheckinInterval: 15000
threadPool: # threadPool:
class: org.quartz.simpl.SimpleThreadPool # class: org.quartz.simpl.SimpleThreadPool
threadCount: 10 # threadCount: 10
threadPriority: 5 # threadPriority: 5
threadsInheritContextClassLoaderOfInitializingThread: true # threadsInheritContextClassLoaderOfInitializingThread: true
#json 时间戳统一转换 #json 时间戳统一转换
jackson: jackson:
date-format: yyyy-MM-dd HH:mm:ss date-format: yyyy-MM-dd HH:mm:ss

View File

@@ -1,101 +0,0 @@
<template>
<view>
<!--标题和返回-->
<cu-custom :bgColor="NavBarColor" isBack :backRouterName="backRouteName">
<block slot="backText">返回</block>
<block slot="content">试验评定</block>
</cu-custom>
<!--表单区域-->
<view>
<form>
<view class="cu-form-group">
<view class="flex align-center">
<view class="title"><text space="ensp">实验ID</text></view>
<input placeholder="请输入实验ID" v-model="model.experimentalId"/>
</view>
</view>
<view class="cu-form-group">
<view class="flex align-center">
<view class="title"><text space="ensp">评审流程:</text></view>
<input placeholder="请输入评审流程" v-model="model.reviewProcess"/>
</view>
</view>
<view class="cu-form-group">
<view class="flex align-center">
<view class="title"><text space="ensp">评审详情(json大字段)</text></view>
<input placeholder="请输入评审详情(json大字段)" v-model="model.reviewDetail"/>
</view>
</view>
<view class="cu-form-group">
<view class="flex align-center">
<view class="title"><text space="ensp">评审结果:</text></view>
<input placeholder="请输入评审结果" v-model="model.reviewResult"/>
</view>
</view>
<view class="padding">
<button class="cu-btn block bg-blue margin-tb-sm lg" @click="onSubmit">
<text v-if="loading" class="cuIcon-loading2 cuIconfont-spin"></text>提交
</button>
</view>
</form>
</view>
</view>
</template>
<script>
import myDate from '@/components/my-componets/my-date.vue'
export default {
name: "ExperimentReviewForm",
components:{ myDate },
props:{
formData:{
type:Object,
default:()=>{},
required:false
}
},
data(){
return {
CustomBar: this.CustomBar,
NavBarColor: this.NavBarColor,
loading:false,
model: {},
backRouteName:'index',
url: {
queryById: "/database/experimentReview/queryById",
add: "/database/experimentReview/add",
edit: "/database/experimentReview/edit",
},
}
},
created(){
this.initFormData();
},
methods:{
initFormData(){
if(this.formData){
let dataId = this.formData.dataId;
this.$http.get(this.url.queryById,{params:{id:dataId}}).then((res)=>{
if(res.data.success){
console.log("表单数据",res);
this.model = res.data.result;
}
})
}
},
onSubmit() {
let myForm = {...this.model};
this.loading = true;
let url = myForm.id?this.url.edit:this.url.add;
this.$http.post(url,myForm).then(res=>{
console.log("res",res)
this.loading = false
this.$Router.push({name:this.backRouteName})
}).catch(()=>{
this.loading = false
});
}
}
}
</script>

View File

@@ -1,44 +0,0 @@
<template>
<view>
<!--标题和返回-->
<cu-custom :bgColor="NavBarColor" isBack>
<block slot="backText">返回</block>
<block slot="content">试验评定</block>
</cu-custom>
<!--滚动加载列表-->
<mescroll-body ref="mescrollRef" bottom="88" @init="mescrollInit" :up="upOption" :down="downOption" @down="downCallback" @up="upCallback">
<view class="cu-list menu">
<view class="cu-item" v-for="(item,index) in list" :key="index" @click="goHome">
<view class="flex" style="width:100%">
<text class="text-lg" style="color: #000;">
{{ item.createBy}}
</text>
</view>
</view>
</view>
</mescroll-body>
</view>
</template>
<script>
import MescrollMixin from "@/components/mescroll-uni/mescroll-mixins.js";
import Mixin from "@/common/mixin/Mixin.js";
export default {
name: '试验评定',
mixins: [MescrollMixin,Mixin],
data() {
return {
CustomBar:this.CustomBar,
NavBarColor:this.NavBarColor,
url: "/database/experimentReview/list",
};
},
methods: {
goHome(){
this.$Router.push({name: "index"})
}
}
}
</script>

View File

@@ -1,119 +0,0 @@
<template>
<view>
<!--标题和返回-->
<cu-custom :bgColor="NavBarColor" isBack :backRouterName="backRouteName">
<block slot="backText">返回</block>
<block slot="content">迁移数据管理</block>
</cu-custom>
<!--表单区域-->
<view>
<form>
<view class="cu-form-group">
<view class="flex align-center">
<view class="title"><text space="ensp">试验类型:</text></view>
<input placeholder="请输入试验类型" v-model="model.type"/>
</view>
</view>
<view class="cu-form-group">
<view class="flex align-center">
<view class="title"><text space="ensp">试验名称:</text></view>
<input placeholder="请输入试验名称" v-model="model.name"/>
</view>
</view>
<view class="cu-form-group">
<view class="flex align-center">
<view class="title"><text space="ensp">委托方:</text></view>
<input placeholder="请输入委托方" v-model="model.client"/>
</view>
</view>
<view class="cu-form-group">
<view class="flex align-center">
<view class="title"><text space="ensp">生产厂家:</text></view>
<input placeholder="请输入生产厂家" v-model="model.manufacturer"/>
</view>
</view>
<view class="cu-form-group">
<view class="flex align-center">
<view class="title"><text space="ensp">试验时间:</text></view>
<input placeholder="请输入试验时间" v-model="model.experimentDate"/>
</view>
</view>
<view class="cu-form-group">
<view class="flex align-center">
<view class="title"><text space="ensp">试验人员:</text></view>
<input placeholder="请输入试验人员" v-model="model.experimentUser"/>
</view>
</view>
<view class="cu-form-group">
<view class="flex align-center">
<view class="title"><text space="ensp">实验详情(大字段)</text></view>
<input placeholder="请输入实验详情(大字段)" v-model="model.experimentDetail"/>
</view>
</view>
<view class="padding">
<button class="cu-btn block bg-blue margin-tb-sm lg" @click="onSubmit">
<text v-if="loading" class="cuIcon-loading2 cuIconfont-spin"></text>提交
</button>
</view>
</form>
</view>
</view>
</template>
<script>
import myDate from '@/components/my-componets/my-date.vue'
export default {
name: "MigrationDataRecordForm",
components:{ myDate },
props:{
formData:{
type:Object,
default:()=>{},
required:false
}
},
data(){
return {
CustomBar: this.CustomBar,
NavBarColor: this.NavBarColor,
loading:false,
model: {},
backRouteName:'index',
url: {
queryById: "/database/migrationDataRecord/queryById",
add: "/database/migrationDataRecord/add",
edit: "/database/migrationDataRecord/edit",
},
}
},
created(){
this.initFormData();
},
methods:{
initFormData(){
if(this.formData){
let dataId = this.formData.dataId;
this.$http.get(this.url.queryById,{params:{id:dataId}}).then((res)=>{
if(res.data.success){
console.log("表单数据",res);
this.model = res.data.result;
}
})
}
},
onSubmit() {
let myForm = {...this.model};
this.loading = true;
let url = myForm.id?this.url.edit:this.url.add;
this.$http.post(url,myForm).then(res=>{
console.log("res",res)
this.loading = false
this.$Router.push({name:this.backRouteName})
}).catch(()=>{
this.loading = false
});
}
}
}
</script>

View File

@@ -1,44 +0,0 @@
<template>
<view>
<!--标题和返回-->
<cu-custom :bgColor="NavBarColor" isBack>
<block slot="backText">返回</block>
<block slot="content">迁移数据管理</block>
</cu-custom>
<!--滚动加载列表-->
<mescroll-body ref="mescrollRef" bottom="88" @init="mescrollInit" :up="upOption" :down="downOption" @down="downCallback" @up="upCallback">
<view class="cu-list menu">
<view class="cu-item" v-for="(item,index) in list" :key="index" @click="goHome">
<view class="flex" style="width:100%">
<text class="text-lg" style="color: #000;">
{{ item.createBy}}
</text>
</view>
</view>
</view>
</mescroll-body>
</view>
</template>
<script>
import MescrollMixin from "@/components/mescroll-uni/mescroll-mixins.js";
import Mixin from "@/common/mixin/Mixin.js";
export default {
name: '迁移数据管理',
mixins: [MescrollMixin,Mixin],
data() {
return {
CustomBar:this.CustomBar,
NavBarColor:this.NavBarColor,
url: "/database/migrationDataRecord/list",
};
},
methods: {
goHome(){
this.$Router.push({name: "index"})
}
}
}
</script>

View File

@@ -1,143 +0,0 @@
<template>
<view>
<!--标题和返回-->
<cu-custom :bgColor="NavBarColor" isBack :backRouterName="backRouteName">
<block slot="backText">返回</block>
<block slot="content">NASA数据管理</block>
</cu-custom>
<!--表单区域-->
<view>
<form>
<view class="cu-form-group">
<view class="flex align-center">
<view class="title"><text space="ensp">器件类型:</text></view>
<input placeholder="请输入器件类型" v-model="model.deviceType"/>
</view>
</view>
<view class="cu-form-group">
<view class="flex align-center">
<view class="title"><text space="ensp">器件名称:</text></view>
<input placeholder="请输入器件名称" v-model="model.deviceName"/>
</view>
</view>
<view class="cu-form-group">
<view class="flex align-center">
<view class="title"><text space="ensp">器件型号:</text></view>
<input placeholder="请输入器件型号" v-model="model.deviceMode"/>
</view>
</view>
<view class="cu-form-group">
<view class="flex align-center">
<view class="title"><text space="ensp">器件功能:</text></view>
<input placeholder="请输入器件功能" v-model="model.deviceFunction"/>
</view>
</view>
<view class="cu-form-group">
<view class="flex align-center">
<view class="title"><text space="ensp">器件批次:</text></view>
<input placeholder="请输入器件批次" v-model="model.deviceBatch"/>
</view>
</view>
<view class="cu-form-group">
<view class="flex align-center">
<view class="title"><text space="ensp">生产厂家:</text></view>
<input placeholder="请输入生产厂家" v-model="model.manufacturer"/>
</view>
</view>
<view class="cu-form-group">
<view class="flex align-center">
<view class="title"><text space="ensp">试验时间:</text></view>
<input placeholder="请输入试验时间" v-model="model.experimentDate"/>
</view>
</view>
<view class="cu-form-group">
<view class="flex align-center">
<view class="title"><text space="ensp">数据来源:</text></view>
<input placeholder="请输入数据来源" v-model="model.dataSource"/>
</view>
</view>
<view class="cu-form-group">
<view class="flex align-center">
<view class="title"><text space="ensp">试验人员:</text></view>
<input placeholder="请输入试验人员" v-model="model.experimentUser"/>
</view>
</view>
<view class="cu-form-group">
<view class="flex align-center">
<view class="title"><text space="ensp">条目数统计:</text></view>
<input placeholder="请输入条目数统计" v-model="model.totalCount"/>
</view>
</view>
<view class="cu-form-group">
<view class="flex align-center">
<view class="title"><text space="ensp">附件IDs</text></view>
<input placeholder="请输入附件IDs" v-model="model.fileList"/>
</view>
</view>
<view class="padding">
<button class="cu-btn block bg-blue margin-tb-sm lg" @click="onSubmit">
<text v-if="loading" class="cuIcon-loading2 cuIconfont-spin"></text>提交
</button>
</view>
</form>
</view>
</view>
</template>
<script>
import myDate from '@/components/my-componets/my-date.vue'
export default {
name: "NasaDataRecordForm",
components:{ myDate },
props:{
formData:{
type:Object,
default:()=>{},
required:false
}
},
data(){
return {
CustomBar: this.CustomBar,
NavBarColor: this.NavBarColor,
loading:false,
model: {},
backRouteName:'index',
url: {
queryById: "/database/nasaDataRecord/queryById",
add: "/database/nasaDataRecord/add",
edit: "/database/nasaDataRecord/edit",
},
}
},
created(){
this.initFormData();
},
methods:{
initFormData(){
if(this.formData){
let dataId = this.formData.dataId;
this.$http.get(this.url.queryById,{params:{id:dataId}}).then((res)=>{
if(res.data.success){
console.log("表单数据",res);
this.model = res.data.result;
}
})
}
},
onSubmit() {
let myForm = {...this.model};
this.loading = true;
let url = myForm.id?this.url.edit:this.url.add;
this.$http.post(url,myForm).then(res=>{
console.log("res",res)
this.loading = false
this.$Router.push({name:this.backRouteName})
}).catch(()=>{
this.loading = false
});
}
}
}
</script>

View File

@@ -1,44 +0,0 @@
<template>
<view>
<!--标题和返回-->
<cu-custom :bgColor="NavBarColor" isBack>
<block slot="backText">返回</block>
<block slot="content">NASA数据管理</block>
</cu-custom>
<!--滚动加载列表-->
<mescroll-body ref="mescrollRef" bottom="88" @init="mescrollInit" :up="upOption" :down="downOption" @down="downCallback" @up="upCallback">
<view class="cu-list menu">
<view class="cu-item" v-for="(item,index) in list" :key="index" @click="goHome">
<view class="flex" style="width:100%">
<text class="text-lg" style="color: #000;">
{{ item.createBy}}
</text>
</view>
</view>
</view>
</mescroll-body>
</view>
</template>
<script>
import MescrollMixin from "@/components/mescroll-uni/mescroll-mixins.js";
import Mixin from "@/common/mixin/Mixin.js";
export default {
name: 'NASA数据管理',
mixins: [MescrollMixin,Mixin],
data() {
return {
CustomBar:this.CustomBar,
NavBarColor:this.NavBarColor,
url: "/database/nasaDataRecord/list",
};
},
methods: {
goHome(){
this.$Router.push({name: "index"})
}
}
}
</script>

View File

@@ -1,64 +0,0 @@
import {defHttp} from '/@/utils/http/axios';
import { useMessage } from "/@/hooks/web/useMessage";
const { createConfirm } = useMessage();
enum Api {
list = '/database/experimentReview/list',
save='/database/experimentReview/add',
edit='/database/experimentReview/edit',
deleteOne = '/database/experimentReview/delete',
deleteBatch = '/database/experimentReview/deleteBatch',
importExcel = '/database/experimentReview/importExcel',
exportXls = '/database/experimentReview/exportXls',
}
/**
* 导出api
* @param params
*/
export const getExportUrl = Api.exportXls;
/**
* 导入api
*/
export const getImportUrl = Api.importExcel;
/**
* 列表接口
* @param params
*/
export const list = (params) =>
defHttp.get({url: Api.list, params});
/**
* 删除单个
*/
export const deleteOne = (params,handleSuccess) => {
return defHttp.delete({url: Api.deleteOne, params}, {joinParamsToUrl: true}).then(() => {
handleSuccess();
});
}
/**
* 批量删除
* @param params
*/
export const batchDelete = (params, handleSuccess) => {
createConfirm({
iconType: 'warning',
title: '确认删除',
content: '是否删除选中数据',
okText: '确认',
cancelText: '取消',
onOk: () => {
return defHttp.delete({url: Api.deleteBatch, data: params}, {joinParamsToUrl: true}).then(() => {
handleSuccess();
});
}
});
}
/**
* 保存或者更新
* @param params
*/
export const saveOrUpdate = (params, isUpdate) => {
let url = isUpdate ? Api.edit : Api.save;
return defHttp.post({url: url, params});
}

View File

@@ -1,78 +0,0 @@
import {BasicColumn} from '/@/components/Table';
import {FormSchema} from '/@/components/Table';
import { rules} from '/@/utils/helper/validator';
import { render } from '/@/utils/common/renderUtils';
import { getWeekMonthQuarterYear } from '/@/utils';
//列表数据
export const columns: BasicColumn[] = [
{
title: '实验ID',
align:"center",
dataIndex: 'experimentalId'
},
{
title: '评审流程',
align:"center",
dataIndex: 'reviewProcess'
},
{
title: '评审详情(json大字段)',
align:"center",
dataIndex: 'reviewDetail'
},
{
title: '评审结果',
align:"center",
dataIndex: 'reviewResult'
},
];
//查询数据
export const searchFormSchema: FormSchema[] = [
];
//表单数据
export const formSchema: FormSchema[] = [
{
label: '实验ID',
field: 'experimentalId',
component: 'Input',
},
{
label: '评审流程',
field: 'reviewProcess',
component: 'Input',
},
{
label: '评审详情(json大字段)',
field: 'reviewDetail',
component: 'Input',
},
{
label: '评审结果',
field: 'reviewResult',
component: 'Input',
},
// TODO 主键隐藏字段目前写死为ID
{
label: '',
field: 'id',
component: 'Input',
show: false
},
];
// 高级查询数据
export const superQuerySchema = {
experimentalId: {title: '实验ID',order: 0,view: 'text', type: 'string',},
reviewProcess: {title: '评审流程',order: 1,view: 'text', type: 'string',},
reviewDetail: {title: '评审详情(json大字段)',order: 2,view: 'text', type: 'string',},
reviewResult: {title: '评审结果',order: 3,view: 'text', type: 'string',},
};
/**
* 流程表单调用这个方法获取formSchema
* @param param
*/
export function getBpmFormSchema(_formData): FormSchema[]{
// 默认和原始表单保持一致 如果流程中配置了权限数据这里需要单独处理formSchema
return formSchema;
}

View File

@@ -1,188 +0,0 @@
<template>
<div>
<!--引用表格-->
<BasicTable @register="registerTable" :rowSelection="rowSelection">
<!--插槽:table标题-->
<template #tableTitle>
<a-button type="primary" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button>
<a-button type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button>
<j-upload-button type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button>
<a-dropdown v-if="selectedRowKeys.length > 0">
<template #overlay>
<a-menu>
<a-menu-item key="1" @click="batchHandleDelete">
<Icon icon="ant-design:delete-outlined"></Icon>
删除
</a-menu-item>
</a-menu>
</template>
<a-button>批量操作
<Icon icon="mdi:chevron-down"></Icon>
</a-button>
</a-dropdown>
<!-- 高级查询 -->
<super-query :config="superQueryConfig" @search="handleSuperQuery" />
</template>
<!--操作栏-->
<template #action="{ record }">
<TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)"/>
</template>
<!--字段回显插槽-->
<template v-slot:bodyCell="{ column, record, index, text }">
</template>
</BasicTable>
<!-- 表单区域 -->
<ExperimentReviewModal @register="registerModal" @success="handleSuccess"></ExperimentReviewModal>
</div>
</template>
<script lang="ts" name="database-experimentReview" setup>
import {ref, reactive, computed, unref} from 'vue';
import {BasicTable, useTable, TableAction} from '/@/components/Table';
import {useModal} from '/@/components/Modal';
import { useListPage } from '/@/hooks/system/useListPage'
import ExperimentReviewModal from './components/ExperimentReviewModal.vue'
import {columns, searchFormSchema, superQuerySchema} from './ExperimentReview.data';
import {list, deleteOne, batchDelete, getImportUrl,getExportUrl} from './ExperimentReview.api';
import { downloadFile } from '/@/utils/common/renderUtils';
import { useUserStore } from '/@/store/modules/user';
const queryParam = reactive<any>({});
const checkedKeys = ref<Array<string | number>>([]);
const userStore = useUserStore();
//注册model
const [registerModal, {openModal}] = useModal();
//注册table数据
const { prefixCls,tableContext,onExportXls,onImportXls } = useListPage({
tableProps:{
title: '试验评定',
api: list,
columns,
canResize:false,
formConfig: {
//labelWidth: 120,
schemas: searchFormSchema,
autoSubmitOnEnter:true,
showAdvancedButton:true,
fieldMapToNumber: [
],
fieldMapToTime: [
],
},
actionColumn: {
width: 120,
fixed:'right'
},
beforeFetch: (params) => {
return Object.assign(params, queryParam);
},
},
exportConfig: {
name:"试验评定",
url: getExportUrl,
params: queryParam,
},
importConfig: {
url: getImportUrl,
success: handleSuccess
},
})
const [registerTable, {reload},{ rowSelection, selectedRowKeys }] = tableContext
// 高级查询配置
const superQueryConfig = reactive(superQuerySchema);
/**
* 高级查询事件
*/
function handleSuperQuery(params) {
Object.keys(params).map((k) => {
queryParam[k] = params[k];
});
reload();
}
/**
* 新增事件
*/
function handleAdd() {
openModal(true, {
isUpdate: false,
showFooter: true,
});
}
/**
* 编辑事件
*/
function handleEdit(record: Recordable) {
openModal(true, {
record,
isUpdate: true,
showFooter: true,
});
}
/**
* 详情
*/
function handleDetail(record: Recordable) {
openModal(true, {
record,
isUpdate: true,
showFooter: false,
});
}
/**
* 删除事件
*/
async function handleDelete(record) {
await deleteOne({id: record.id}, handleSuccess);
}
/**
* 批量删除事件
*/
async function batchHandleDelete() {
await batchDelete({ids: selectedRowKeys.value}, handleSuccess);
}
/**
* 成功回调
*/
function handleSuccess() {
(selectedRowKeys.value = []) && reload();
}
/**
* 操作栏
*/
function getTableAction(record){
return [
{
label: '编辑',
onClick: handleEdit.bind(null, record),
}
]
}
/**
* 下拉操作栏
*/
function getDropDownAction(record){
return [
{
label: '详情',
onClick: handleDetail.bind(null, record),
}, {
label: '删除',
popConfirm: {
title: '是否确认删除',
confirm: handleDelete.bind(null, record),
placement: 'topLeft',
}
}
]
}
</script>
<style scoped>
:deep(.ant-picker),:deep(.ant-input-number){
width: 100%;
}
</style>

View File

@@ -1,64 +0,0 @@
import {defHttp} from '/@/utils/http/axios';
import { useMessage } from "/@/hooks/web/useMessage";
const { createConfirm } = useMessage();
enum Api {
list = '/database/migrationDataRecord/list',
save='/database/migrationDataRecord/add',
edit='/database/migrationDataRecord/edit',
deleteOne = '/database/migrationDataRecord/delete',
deleteBatch = '/database/migrationDataRecord/deleteBatch',
importExcel = '/database/migrationDataRecord/importExcel',
exportXls = '/database/migrationDataRecord/exportXls',
}
/**
* 导出api
* @param params
*/
export const getExportUrl = Api.exportXls;
/**
* 导入api
*/
export const getImportUrl = Api.importExcel;
/**
* 列表接口
* @param params
*/
export const list = (params) =>
defHttp.get({url: Api.list, params});
/**
* 删除单个
*/
export const deleteOne = (params,handleSuccess) => {
return defHttp.delete({url: Api.deleteOne, params}, {joinParamsToUrl: true}).then(() => {
handleSuccess();
});
}
/**
* 批量删除
* @param params
*/
export const batchDelete = (params, handleSuccess) => {
createConfirm({
iconType: 'warning',
title: '确认删除',
content: '是否删除选中数据',
okText: '确认',
cancelText: '取消',
onOk: () => {
return defHttp.delete({url: Api.deleteBatch, data: params}, {joinParamsToUrl: true}).then(() => {
handleSuccess();
});
}
});
}
/**
* 保存或者更新
* @param params
*/
export const saveOrUpdate = (params, isUpdate) => {
let url = isUpdate ? Api.edit : Api.save;
return defHttp.post({url: url, params});
}

View File

@@ -1,111 +0,0 @@
import {BasicColumn} from '/@/components/Table';
import {FormSchema} from '/@/components/Table';
import { rules} from '/@/utils/helper/validator';
import { render } from '/@/utils/common/renderUtils';
import { getWeekMonthQuarterYear } from '/@/utils';
//列表数据
export const columns: BasicColumn[] = [
{
title: '试验类型',
align:"center",
dataIndex: 'type'
},
{
title: '试验名称',
align:"center",
dataIndex: 'name'
},
{
title: '委托方',
align:"center",
dataIndex: 'client'
},
{
title: '生产厂家',
align:"center",
dataIndex: 'manufacturer'
},
{
title: '试验时间',
align:"center",
dataIndex: 'experimentDate'
},
{
title: '试验人员',
align:"center",
dataIndex: 'experimentUser'
},
{
title: '实验详情(大字段)',
align:"center",
dataIndex: 'experimentDetail'
},
];
//查询数据
export const searchFormSchema: FormSchema[] = [
];
//表单数据
export const formSchema: FormSchema[] = [
{
label: '试验类型',
field: 'type',
component: 'Input',
},
{
label: '试验名称',
field: 'name',
component: 'Input',
},
{
label: '委托方',
field: 'client',
component: 'Input',
},
{
label: '生产厂家',
field: 'manufacturer',
component: 'Input',
},
{
label: '试验时间',
field: 'experimentDate',
component: 'Input',
},
{
label: '试验人员',
field: 'experimentUser',
component: 'Input',
},
{
label: '实验详情(大字段)',
field: 'experimentDetail',
component: 'Input',
},
// TODO 主键隐藏字段目前写死为ID
{
label: '',
field: 'id',
component: 'Input',
show: false
},
];
// 高级查询数据
export const superQuerySchema = {
type: {title: '试验类型',order: 0,view: 'text', type: 'string',},
name: {title: '试验名称',order: 1,view: 'text', type: 'string',},
client: {title: '委托方',order: 2,view: 'text', type: 'string',},
manufacturer: {title: '生产厂家',order: 3,view: 'text', type: 'string',},
experimentDate: {title: '试验时间',order: 4,view: 'text', type: 'string',},
experimentUser: {title: '试验人员',order: 5,view: 'text', type: 'string',},
experimentDetail: {title: '实验详情(大字段)',order: 6,view: 'text', type: 'string',},
};
/**
* 流程表单调用这个方法获取formSchema
* @param param
*/
export function getBpmFormSchema(_formData): FormSchema[]{
// 默认和原始表单保持一致 如果流程中配置了权限数据这里需要单独处理formSchema
return formSchema;
}

View File

@@ -1,188 +0,0 @@
<template>
<div>
<!--引用表格-->
<BasicTable @register="registerTable" :rowSelection="rowSelection">
<!--插槽:table标题-->
<template #tableTitle>
<a-button type="primary" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button>
<a-button type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button>
<j-upload-button type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button>
<a-dropdown v-if="selectedRowKeys.length > 0">
<template #overlay>
<a-menu>
<a-menu-item key="1" @click="batchHandleDelete">
<Icon icon="ant-design:delete-outlined"></Icon>
删除
</a-menu-item>
</a-menu>
</template>
<a-button>批量操作
<Icon icon="mdi:chevron-down"></Icon>
</a-button>
</a-dropdown>
<!-- 高级查询 -->
<super-query :config="superQueryConfig" @search="handleSuperQuery" />
</template>
<!--操作栏-->
<template #action="{ record }">
<TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)"/>
</template>
<!--字段回显插槽-->
<template v-slot:bodyCell="{ column, record, index, text }">
</template>
</BasicTable>
<!-- 表单区域 -->
<MigrationDataRecordModal @register="registerModal" @success="handleSuccess"></MigrationDataRecordModal>
</div>
</template>
<script lang="ts" name="database-migrationDataRecord" setup>
import {ref, reactive, computed, unref} from 'vue';
import {BasicTable, useTable, TableAction} from '/@/components/Table';
import {useModal} from '/@/components/Modal';
import { useListPage } from '/@/hooks/system/useListPage'
import MigrationDataRecordModal from './components/MigrationDataRecordModal.vue'
import {columns, searchFormSchema, superQuerySchema} from './MigrationDataRecord.data';
import {list, deleteOne, batchDelete, getImportUrl,getExportUrl} from './MigrationDataRecord.api';
import { downloadFile } from '/@/utils/common/renderUtils';
import { useUserStore } from '/@/store/modules/user';
const queryParam = reactive<any>({});
const checkedKeys = ref<Array<string | number>>([]);
const userStore = useUserStore();
//注册model
const [registerModal, {openModal}] = useModal();
//注册table数据
const { prefixCls,tableContext,onExportXls,onImportXls } = useListPage({
tableProps:{
title: '迁移数据管理',
api: list,
columns,
canResize:false,
formConfig: {
//labelWidth: 120,
schemas: searchFormSchema,
autoSubmitOnEnter:true,
showAdvancedButton:true,
fieldMapToNumber: [
],
fieldMapToTime: [
],
},
actionColumn: {
width: 120,
fixed:'right'
},
beforeFetch: (params) => {
return Object.assign(params, queryParam);
},
},
exportConfig: {
name:"迁移数据管理",
url: getExportUrl,
params: queryParam,
},
importConfig: {
url: getImportUrl,
success: handleSuccess
},
})
const [registerTable, {reload},{ rowSelection, selectedRowKeys }] = tableContext
// 高级查询配置
const superQueryConfig = reactive(superQuerySchema);
/**
* 高级查询事件
*/
function handleSuperQuery(params) {
Object.keys(params).map((k) => {
queryParam[k] = params[k];
});
reload();
}
/**
* 新增事件
*/
function handleAdd() {
openModal(true, {
isUpdate: false,
showFooter: true,
});
}
/**
* 编辑事件
*/
function handleEdit(record: Recordable) {
openModal(true, {
record,
isUpdate: true,
showFooter: true,
});
}
/**
* 详情
*/
function handleDetail(record: Recordable) {
openModal(true, {
record,
isUpdate: true,
showFooter: false,
});
}
/**
* 删除事件
*/
async function handleDelete(record) {
await deleteOne({id: record.id}, handleSuccess);
}
/**
* 批量删除事件
*/
async function batchHandleDelete() {
await batchDelete({ids: selectedRowKeys.value}, handleSuccess);
}
/**
* 成功回调
*/
function handleSuccess() {
(selectedRowKeys.value = []) && reload();
}
/**
* 操作栏
*/
function getTableAction(record){
return [
{
label: '编辑',
onClick: handleEdit.bind(null, record),
}
]
}
/**
* 下拉操作栏
*/
function getDropDownAction(record){
return [
{
label: '详情',
onClick: handleDetail.bind(null, record),
}, {
label: '删除',
popConfirm: {
title: '是否确认删除',
confirm: handleDelete.bind(null, record),
placement: 'topLeft',
}
}
]
}
</script>
<style scoped>
:deep(.ant-picker),:deep(.ant-input-number){
width: 100%;
}
</style>

View File

@@ -1,64 +0,0 @@
import {defHttp} from '/@/utils/http/axios';
import { useMessage } from "/@/hooks/web/useMessage";
const { createConfirm } = useMessage();
enum Api {
list = '/database/nasaDataRecord/list',
save='/database/nasaDataRecord/add',
edit='/database/nasaDataRecord/edit',
deleteOne = '/database/nasaDataRecord/delete',
deleteBatch = '/database/nasaDataRecord/deleteBatch',
importExcel = '/database/nasaDataRecord/importExcel',
exportXls = '/database/nasaDataRecord/exportXls',
}
/**
* 导出api
* @param params
*/
export const getExportUrl = Api.exportXls;
/**
* 导入api
*/
export const getImportUrl = Api.importExcel;
/**
* 列表接口
* @param params
*/
export const list = (params) =>
defHttp.get({url: Api.list, params});
/**
* 删除单个
*/
export const deleteOne = (params,handleSuccess) => {
return defHttp.delete({url: Api.deleteOne, params}, {joinParamsToUrl: true}).then(() => {
handleSuccess();
});
}
/**
* 批量删除
* @param params
*/
export const batchDelete = (params, handleSuccess) => {
createConfirm({
iconType: 'warning',
title: '确认删除',
content: '是否删除选中数据',
okText: '确认',
cancelText: '取消',
onOk: () => {
return defHttp.delete({url: Api.deleteBatch, data: params}, {joinParamsToUrl: true}).then(() => {
handleSuccess();
});
}
});
}
/**
* 保存或者更新
* @param params
*/
export const saveOrUpdate = (params, isUpdate) => {
let url = isUpdate ? Api.edit : Api.save;
return defHttp.post({url: url, params});
}

View File

@@ -1,155 +0,0 @@
import {BasicColumn} from '/@/components/Table';
import {FormSchema} from '/@/components/Table';
import { rules} from '/@/utils/helper/validator';
import { render } from '/@/utils/common/renderUtils';
import { getWeekMonthQuarterYear } from '/@/utils';
//列表数据
export const columns: BasicColumn[] = [
{
title: '器件类型',
align:"center",
dataIndex: 'deviceType'
},
{
title: '器件名称',
align:"center",
dataIndex: 'deviceName'
},
{
title: '器件型号',
align:"center",
dataIndex: 'deviceMode'
},
{
title: '器件功能',
align:"center",
dataIndex: 'deviceFunction'
},
{
title: '器件批次',
align:"center",
dataIndex: 'deviceBatch'
},
{
title: '生产厂家',
align:"center",
dataIndex: 'manufacturer'
},
{
title: '试验时间',
align:"center",
dataIndex: 'experimentDate'
},
{
title: '数据来源',
align:"center",
dataIndex: 'dataSource'
},
{
title: '试验人员',
align:"center",
dataIndex: 'experimentUser'
},
{
title: '条目数统计',
align:"center",
dataIndex: 'totalCount'
},
{
title: '附件IDs',
align:"center",
dataIndex: 'fileList'
},
];
//查询数据
export const searchFormSchema: FormSchema[] = [
];
//表单数据
export const formSchema: FormSchema[] = [
{
label: '器件类型',
field: 'deviceType',
component: 'Input',
},
{
label: '器件名称',
field: 'deviceName',
component: 'Input',
},
{
label: '器件型号',
field: 'deviceMode',
component: 'Input',
},
{
label: '器件功能',
field: 'deviceFunction',
component: 'Input',
},
{
label: '器件批次',
field: 'deviceBatch',
component: 'Input',
},
{
label: '生产厂家',
field: 'manufacturer',
component: 'Input',
},
{
label: '试验时间',
field: 'experimentDate',
component: 'Input',
},
{
label: '数据来源',
field: 'dataSource',
component: 'Input',
},
{
label: '试验人员',
field: 'experimentUser',
component: 'Input',
},
{
label: '条目数统计',
field: 'totalCount',
component: 'Input',
},
{
label: '附件IDs',
field: 'fileList',
component: 'Input',
},
// TODO 主键隐藏字段目前写死为ID
{
label: '',
field: 'id',
component: 'Input',
show: false
},
];
// 高级查询数据
export const superQuerySchema = {
deviceType: {title: '器件类型',order: 0,view: 'text', type: 'string',},
deviceName: {title: '器件名称',order: 1,view: 'text', type: 'string',},
deviceMode: {title: '器件型号',order: 2,view: 'text', type: 'string',},
deviceFunction: {title: '器件功能',order: 3,view: 'text', type: 'string',},
deviceBatch: {title: '器件批次',order: 4,view: 'text', type: 'string',},
manufacturer: {title: '生产厂家',order: 5,view: 'text', type: 'string',},
experimentDate: {title: '试验时间',order: 6,view: 'text', type: 'string',},
dataSource: {title: '数据来源',order: 7,view: 'text', type: 'string',},
experimentUser: {title: '试验人员',order: 8,view: 'text', type: 'string',},
totalCount: {title: '条目数统计',order: 9,view: 'text', type: 'string',},
fileList: {title: '附件IDs',order: 10,view: 'text', type: 'string',},
};
/**
* 流程表单调用这个方法获取formSchema
* @param param
*/
export function getBpmFormSchema(_formData): FormSchema[]{
// 默认和原始表单保持一致 如果流程中配置了权限数据这里需要单独处理formSchema
return formSchema;
}

View File

@@ -1,188 +0,0 @@
<template>
<div>
<!--引用表格-->
<BasicTable @register="registerTable" :rowSelection="rowSelection">
<!--插槽:table标题-->
<template #tableTitle>
<a-button type="primary" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button>
<a-button type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button>
<j-upload-button type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button>
<a-dropdown v-if="selectedRowKeys.length > 0">
<template #overlay>
<a-menu>
<a-menu-item key="1" @click="batchHandleDelete">
<Icon icon="ant-design:delete-outlined"></Icon>
删除
</a-menu-item>
</a-menu>
</template>
<a-button>批量操作
<Icon icon="mdi:chevron-down"></Icon>
</a-button>
</a-dropdown>
<!-- 高级查询 -->
<super-query :config="superQueryConfig" @search="handleSuperQuery" />
</template>
<!--操作栏-->
<template #action="{ record }">
<TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)"/>
</template>
<!--字段回显插槽-->
<template v-slot:bodyCell="{ column, record, index, text }">
</template>
</BasicTable>
<!-- 表单区域 -->
<NasaDataRecordModal @register="registerModal" @success="handleSuccess"></NasaDataRecordModal>
</div>
</template>
<script lang="ts" name="database-nasaDataRecord" setup>
import {ref, reactive, computed, unref} from 'vue';
import {BasicTable, useTable, TableAction} from '/@/components/Table';
import {useModal} from '/@/components/Modal';
import { useListPage } from '/@/hooks/system/useListPage'
import NasaDataRecordModal from './components/NasaDataRecordModal.vue'
import {columns, searchFormSchema, superQuerySchema} from './NasaDataRecord.data';
import {list, deleteOne, batchDelete, getImportUrl,getExportUrl} from './NasaDataRecord.api';
import { downloadFile } from '/@/utils/common/renderUtils';
import { useUserStore } from '/@/store/modules/user';
const queryParam = reactive<any>({});
const checkedKeys = ref<Array<string | number>>([]);
const userStore = useUserStore();
//注册model
const [registerModal, {openModal}] = useModal();
//注册table数据
const { prefixCls,tableContext,onExportXls,onImportXls } = useListPage({
tableProps:{
title: 'NASA数据管理',
api: list,
columns,
canResize:false,
formConfig: {
//labelWidth: 120,
schemas: searchFormSchema,
autoSubmitOnEnter:true,
showAdvancedButton:true,
fieldMapToNumber: [
],
fieldMapToTime: [
],
},
actionColumn: {
width: 120,
fixed:'right'
},
beforeFetch: (params) => {
return Object.assign(params, queryParam);
},
},
exportConfig: {
name:"NASA数据管理",
url: getExportUrl,
params: queryParam,
},
importConfig: {
url: getImportUrl,
success: handleSuccess
},
})
const [registerTable, {reload},{ rowSelection, selectedRowKeys }] = tableContext
// 高级查询配置
const superQueryConfig = reactive(superQuerySchema);
/**
* 高级查询事件
*/
function handleSuperQuery(params) {
Object.keys(params).map((k) => {
queryParam[k] = params[k];
});
reload();
}
/**
* 新增事件
*/
function handleAdd() {
openModal(true, {
isUpdate: false,
showFooter: true,
});
}
/**
* 编辑事件
*/
function handleEdit(record: Recordable) {
openModal(true, {
record,
isUpdate: true,
showFooter: true,
});
}
/**
* 详情
*/
function handleDetail(record: Recordable) {
openModal(true, {
record,
isUpdate: true,
showFooter: false,
});
}
/**
* 删除事件
*/
async function handleDelete(record) {
await deleteOne({id: record.id}, handleSuccess);
}
/**
* 批量删除事件
*/
async function batchHandleDelete() {
await batchDelete({ids: selectedRowKeys.value}, handleSuccess);
}
/**
* 成功回调
*/
function handleSuccess() {
(selectedRowKeys.value = []) && reload();
}
/**
* 操作栏
*/
function getTableAction(record){
return [
{
label: '编辑',
onClick: handleEdit.bind(null, record),
}
]
}
/**
* 下拉操作栏
*/
function getDropDownAction(record){
return [
{
label: '详情',
onClick: handleDetail.bind(null, record),
}, {
label: '删除',
popConfirm: {
title: '是否确认删除',
confirm: handleDelete.bind(null, record),
placement: 'topLeft',
}
}
]
}
</script>
<style scoped>
:deep(.ant-picker),:deep(.ant-input-number){
width: 100%;
}
</style>

View File

@@ -1,26 +0,0 @@
-- 注意该页面对应的前台目录为views/database文件夹下
-- 如果你想更改到其他目录请修改sql中component字段对应的值
INSERT INTO sys_permission(id, parent_id, name, url, component, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_route, is_leaf, keep_alive, hidden, hide_tab, description, status, del_flag, rule_flag, create_by, create_time, update_by, update_time, internal_or_external)
VALUES ('2024110401285550100', NULL, '迁移数据管理', '/database/migrationDataRecordList', 'database/MigrationDataRecordList', NULL, NULL, 0, NULL, '1', 0.00, 0, NULL, 1, 0, 0, 0, 0, NULL, '1', 0, 0, 'admin', '2024-11-04 13:28:10', NULL, NULL, 0);
-- 权限控制sql
-- 新增
INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
VALUES ('2024110401285550101', '2024110401285550100', '添加迁移数据管理', NULL, NULL, 0, NULL, NULL, 2, 'database:migration_data_record:add', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2024-11-04 13:28:10', NULL, NULL, 0, 0, '1', 0);
-- 编辑
INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
VALUES ('2024110401285550102', '2024110401285550100', '编辑迁移数据管理', NULL, NULL, 0, NULL, NULL, 2, 'database:migration_data_record:edit', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2024-11-04 13:28:10', NULL, NULL, 0, 0, '1', 0);
-- 删除
INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
VALUES ('2024110401285550103', '2024110401285550100', '删除迁移数据管理', NULL, NULL, 0, NULL, NULL, 2, 'database:migration_data_record:delete', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2024-11-04 13:28:10', NULL, NULL, 0, 0, '1', 0);
-- 批量删除
INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
VALUES ('2024110401285550104', '2024110401285550100', '批量删除迁移数据管理', NULL, NULL, 0, NULL, NULL, 2, 'database:migration_data_record:deleteBatch', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2024-11-04 13:28:10', NULL, NULL, 0, 0, '1', 0);
-- 导出excel
INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
VALUES ('2024110401285550105', '2024110401285550100', '导出excel_迁移数据管理', NULL, NULL, 0, NULL, NULL, 2, 'database:migration_data_record:exportXls', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2024-11-04 13:28:10', NULL, NULL, 0, 0, '1', 0);
-- 导入excel
INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
VALUES ('2024110401285550106', '2024110401285550100', '导入excel_迁移数据管理', NULL, NULL, 0, NULL, NULL, 2, 'database:migration_data_record:importExcel', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2024-11-04 13:28:10', NULL, NULL, 0, 0, '1', 0);

View File

@@ -1,26 +0,0 @@
-- 注意该页面对应的前台目录为views/database文件夹下
-- 如果你想更改到其他目录请修改sql中component字段对应的值
INSERT INTO sys_permission(id, parent_id, name, url, component, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_route, is_leaf, keep_alive, hidden, hide_tab, description, status, del_flag, rule_flag, create_by, create_time, update_by, update_time, internal_or_external)
VALUES ('2024110401279790110', NULL, 'NASA数据管理', '/database/nasaDataRecordList', 'database/NasaDataRecordList', NULL, NULL, 0, NULL, '1', 0.00, 0, NULL, 1, 0, 0, 0, 0, NULL, '1', 0, 0, 'admin', '2024-11-04 13:27:11', NULL, NULL, 0);
-- 权限控制sql
-- 新增
INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
VALUES ('2024110401279800111', '2024110401279790110', '添加NASA数据管理', NULL, NULL, 0, NULL, NULL, 2, 'database:nasa_data_record:add', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2024-11-04 13:27:11', NULL, NULL, 0, 0, '1', 0);
-- 编辑
INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
VALUES ('2024110401279800112', '2024110401279790110', '编辑NASA数据管理', NULL, NULL, 0, NULL, NULL, 2, 'database:nasa_data_record:edit', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2024-11-04 13:27:11', NULL, NULL, 0, 0, '1', 0);
-- 删除
INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
VALUES ('2024110401279800113', '2024110401279790110', '删除NASA数据管理', NULL, NULL, 0, NULL, NULL, 2, 'database:nasa_data_record:delete', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2024-11-04 13:27:11', NULL, NULL, 0, 0, '1', 0);
-- 批量删除
INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
VALUES ('2024110401279800114', '2024110401279790110', '批量删除NASA数据管理', NULL, NULL, 0, NULL, NULL, 2, 'database:nasa_data_record:deleteBatch', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2024-11-04 13:27:11', NULL, NULL, 0, 0, '1', 0);
-- 导出excel
INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
VALUES ('2024110401279800115', '2024110401279790110', '导出excel_NASA数据管理', NULL, NULL, 0, NULL, NULL, 2, 'database:nasa_data_record:exportXls', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2024-11-04 13:27:11', NULL, NULL, 0, 0, '1', 0);
-- 导入excel
INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
VALUES ('2024110401279800116', '2024110401279790110', '导入excel_NASA数据管理', NULL, NULL, 0, NULL, NULL, 2, 'database:nasa_data_record:importExcel', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2024-11-04 13:27:11', NULL, NULL, 0, 0, '1', 0);

View File

@@ -1,26 +0,0 @@
-- 注意该页面对应的前台目录为views/database文件夹下
-- 如果你想更改到其他目录请修改sql中component字段对应的值
INSERT INTO sys_permission(id, parent_id, name, url, component, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_route, is_leaf, keep_alive, hidden, hide_tab, description, status, del_flag, rule_flag, create_by, create_time, update_by, update_time, internal_or_external)
VALUES ('2024110502579840310', NULL, '试验评定', '/database/experimentReviewList', 'database/ExperimentReviewList', NULL, NULL, 0, NULL, '1', 0.00, 0, NULL, 1, 0, 0, 0, 0, NULL, '1', 0, 0, 'admin', '2024-11-05 02:57:31', NULL, NULL, 0);
-- 权限控制sql
-- 新增
INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
VALUES ('2024110502579850311', '2024110502579840310', '添加试验评定', NULL, NULL, 0, NULL, NULL, 2, 'database:experiment_review:add', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2024-11-05 02:57:31', NULL, NULL, 0, 0, '1', 0);
-- 编辑
INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
VALUES ('2024110502579850312', '2024110502579840310', '编辑试验评定', NULL, NULL, 0, NULL, NULL, 2, 'database:experiment_review:edit', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2024-11-05 02:57:31', NULL, NULL, 0, 0, '1', 0);
-- 删除
INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
VALUES ('2024110502579850313', '2024110502579840310', '删除试验评定', NULL, NULL, 0, NULL, NULL, 2, 'database:experiment_review:delete', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2024-11-05 02:57:31', NULL, NULL, 0, 0, '1', 0);
-- 批量删除
INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
VALUES ('2024110502579850314', '2024110502579840310', '批量删除试验评定', NULL, NULL, 0, NULL, NULL, 2, 'database:experiment_review:deleteBatch', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2024-11-05 02:57:31', NULL, NULL, 0, 0, '1', 0);
-- 导出excel
INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
VALUES ('2024110502579850315', '2024110502579840310', '导出excel_试验评定', NULL, NULL, 0, NULL, NULL, 2, 'database:experiment_review:exportXls', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2024-11-05 02:57:31', NULL, NULL, 0, 0, '1', 0);
-- 导入excel
INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
VALUES ('2024110502579850316', '2024110502579840310', '导入excel_试验评定', NULL, NULL, 0, NULL, NULL, 2, 'database:experiment_review:importExcel', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2024-11-05 02:57:31', NULL, NULL, 0, 0, '1', 0);

View File

@@ -1,70 +0,0 @@
<template>
<div style="min-height: 400px">
<BasicForm @register="registerForm"></BasicForm>
<div style="width: 100%;text-align: center" v-if="!formDisabled">
<a-button @click="submitForm" pre-icon="ant-design:check" type="primary"> </a-button>
</div>
</div>
</template>
<script lang="ts">
import {BasicForm, useForm} from '/@/components/Form/index';
import {computed, defineComponent} from 'vue';
import {defHttp} from '/@/utils/http/axios';
import { propTypes } from '/@/utils/propTypes';
import {getBpmFormSchema} from '../ExperimentReview.data';
import {saveOrUpdate} from '../ExperimentReview.api';
export default defineComponent({
name: "ExperimentReviewForm",
components:{
BasicForm
},
props:{
formData: propTypes.object.def({}),
formBpm: propTypes.bool.def(true),
},
setup(props){
const [registerForm, { setFieldsValue, setProps, getFieldsValue }] = useForm({
labelWidth: 150,
schemas: getBpmFormSchema(props.formData),
showActionButtonGroup: false,
baseColProps: {span: 24}
});
const formDisabled = computed(()=>{
if(props.formData.disabled === false){
return false;
}
return true;
});
let formData = {};
const queryByIdUrl = '/database/experimentReview/queryById';
async function initFormData(){
let params = {id: props.formData.dataId};
const data = await defHttp.get({url: queryByIdUrl, params});
formData = {...data}
//设置表单的值
await setFieldsValue(formData);
//默认是禁用
await setProps({disabled: formDisabled.value})
}
async function submitForm() {
let data = getFieldsValue();
let params = Object.assign({}, formData, data);
console.log('表单数据', params)
await saveOrUpdate(params, true)
}
initFormData();
return {
registerForm,
formDisabled,
submitForm,
}
}
});
</script>

View File

@@ -1,68 +0,0 @@
<template>
<BasicModal v-bind="$attrs" @register="registerModal" destroyOnClose :title="title" :width="800" @ok="handleSubmit">
<BasicForm @register="registerForm"/>
</BasicModal>
</template>
<script lang="ts" setup>
import {ref, computed, unref} from 'vue';
import {BasicModal, useModalInner} from '/@/components/Modal';
import {BasicForm, useForm} from '/@/components/Form/index';
import {formSchema} from '../ExperimentReview.data';
import {saveOrUpdate} from '../ExperimentReview.api';
// Emits声明
const emit = defineEmits(['register','success']);
const isUpdate = ref(true);
const isDetail = ref(false);
//表单配置
const [registerForm, {setProps,resetFields, setFieldsValue, validate}] = useForm({
//labelWidth: 150,
schemas: formSchema,
showActionButtonGroup: false,
baseColProps: {span: 24}
});
//表单赋值
const [registerModal, {setModalProps, closeModal}] = useModalInner(async (data) => {
//重置表单
await resetFields();
setModalProps({confirmLoading: false,showCancelBtn:!!data?.showFooter,showOkBtn:!!data?.showFooter});
isUpdate.value = !!data?.isUpdate;
isDetail.value = !!data?.showFooter;
if (unref(isUpdate)) {
//表单赋值
await setFieldsValue({
...data.record,
});
}
// 隐藏底部时禁用整个表单
setProps({ disabled: !data?.showFooter })
});
//设置标题
const title = computed(() => (!unref(isUpdate) ? '新增' : !unref(isDetail) ? '详情' : '编辑'));
//表单提交事件
async function handleSubmit(v) {
try {
let values = await validate();
setModalProps({confirmLoading: true});
//提交表单
await saveOrUpdate(values, isUpdate.value);
//关闭弹窗
closeModal();
//刷新列表
emit('success');
} finally {
setModalProps({confirmLoading: false});
}
}
</script>
<style lang="less" scoped>
/** 时间和数字输入框样式 */
:deep(.ant-input-number) {
width: 100%;
}
:deep(.ant-calendar-picker) {
width: 100%;
}
</style>

View File

@@ -1,70 +0,0 @@
<template>
<div style="min-height: 400px">
<BasicForm @register="registerForm"></BasicForm>
<div style="width: 100%;text-align: center" v-if="!formDisabled">
<a-button @click="submitForm" pre-icon="ant-design:check" type="primary"> </a-button>
</div>
</div>
</template>
<script lang="ts">
import {BasicForm, useForm} from '/@/components/Form/index';
import {computed, defineComponent} from 'vue';
import {defHttp} from '/@/utils/http/axios';
import { propTypes } from '/@/utils/propTypes';
import {getBpmFormSchema} from '../MigrationDataRecord.data';
import {saveOrUpdate} from '../MigrationDataRecord.api';
export default defineComponent({
name: "MigrationDataRecordForm",
components:{
BasicForm
},
props:{
formData: propTypes.object.def({}),
formBpm: propTypes.bool.def(true),
},
setup(props){
const [registerForm, { setFieldsValue, setProps, getFieldsValue }] = useForm({
labelWidth: 150,
schemas: getBpmFormSchema(props.formData),
showActionButtonGroup: false,
baseColProps: {span: 24}
});
const formDisabled = computed(()=>{
if(props.formData.disabled === false){
return false;
}
return true;
});
let formData = {};
const queryByIdUrl = '/database/migrationDataRecord/queryById';
async function initFormData(){
let params = {id: props.formData.dataId};
const data = await defHttp.get({url: queryByIdUrl, params});
formData = {...data}
//设置表单的值
await setFieldsValue(formData);
//默认是禁用
await setProps({disabled: formDisabled.value})
}
async function submitForm() {
let data = getFieldsValue();
let params = Object.assign({}, formData, data);
console.log('表单数据', params)
await saveOrUpdate(params, true)
}
initFormData();
return {
registerForm,
formDisabled,
submitForm,
}
}
});
</script>

View File

@@ -1,68 +0,0 @@
<template>
<BasicModal v-bind="$attrs" @register="registerModal" destroyOnClose :title="title" :width="800" @ok="handleSubmit">
<BasicForm @register="registerForm"/>
</BasicModal>
</template>
<script lang="ts" setup>
import {ref, computed, unref} from 'vue';
import {BasicModal, useModalInner} from '/@/components/Modal';
import {BasicForm, useForm} from '/@/components/Form/index';
import {formSchema} from '../MigrationDataRecord.data';
import {saveOrUpdate} from '../MigrationDataRecord.api';
// Emits声明
const emit = defineEmits(['register','success']);
const isUpdate = ref(true);
const isDetail = ref(false);
//表单配置
const [registerForm, {setProps,resetFields, setFieldsValue, validate}] = useForm({
//labelWidth: 150,
schemas: formSchema,
showActionButtonGroup: false,
baseColProps: {span: 24}
});
//表单赋值
const [registerModal, {setModalProps, closeModal}] = useModalInner(async (data) => {
//重置表单
await resetFields();
setModalProps({confirmLoading: false,showCancelBtn:!!data?.showFooter,showOkBtn:!!data?.showFooter});
isUpdate.value = !!data?.isUpdate;
isDetail.value = !!data?.showFooter;
if (unref(isUpdate)) {
//表单赋值
await setFieldsValue({
...data.record,
});
}
// 隐藏底部时禁用整个表单
setProps({ disabled: !data?.showFooter })
});
//设置标题
const title = computed(() => (!unref(isUpdate) ? '新增' : !unref(isDetail) ? '详情' : '编辑'));
//表单提交事件
async function handleSubmit(v) {
try {
let values = await validate();
setModalProps({confirmLoading: true});
//提交表单
await saveOrUpdate(values, isUpdate.value);
//关闭弹窗
closeModal();
//刷新列表
emit('success');
} finally {
setModalProps({confirmLoading: false});
}
}
</script>
<style lang="less" scoped>
/** 时间和数字输入框样式 */
:deep(.ant-input-number) {
width: 100%;
}
:deep(.ant-calendar-picker) {
width: 100%;
}
</style>

View File

@@ -1,70 +0,0 @@
<template>
<div style="min-height: 400px">
<BasicForm @register="registerForm"></BasicForm>
<div style="width: 100%;text-align: center" v-if="!formDisabled">
<a-button @click="submitForm" pre-icon="ant-design:check" type="primary"> </a-button>
</div>
</div>
</template>
<script lang="ts">
import {BasicForm, useForm} from '/@/components/Form/index';
import {computed, defineComponent} from 'vue';
import {defHttp} from '/@/utils/http/axios';
import { propTypes } from '/@/utils/propTypes';
import {getBpmFormSchema} from '../NasaDataRecord.data';
import {saveOrUpdate} from '../NasaDataRecord.api';
export default defineComponent({
name: "NasaDataRecordForm",
components:{
BasicForm
},
props:{
formData: propTypes.object.def({}),
formBpm: propTypes.bool.def(true),
},
setup(props){
const [registerForm, { setFieldsValue, setProps, getFieldsValue }] = useForm({
labelWidth: 150,
schemas: getBpmFormSchema(props.formData),
showActionButtonGroup: false,
baseColProps: {span: 24}
});
const formDisabled = computed(()=>{
if(props.formData.disabled === false){
return false;
}
return true;
});
let formData = {};
const queryByIdUrl = '/database/nasaDataRecord/queryById';
async function initFormData(){
let params = {id: props.formData.dataId};
const data = await defHttp.get({url: queryByIdUrl, params});
formData = {...data}
//设置表单的值
await setFieldsValue(formData);
//默认是禁用
await setProps({disabled: formDisabled.value})
}
async function submitForm() {
let data = getFieldsValue();
let params = Object.assign({}, formData, data);
console.log('表单数据', params)
await saveOrUpdate(params, true)
}
initFormData();
return {
registerForm,
formDisabled,
submitForm,
}
}
});
</script>

View File

@@ -1,68 +0,0 @@
<template>
<BasicModal v-bind="$attrs" @register="registerModal" destroyOnClose :title="title" :width="800" @ok="handleSubmit">
<BasicForm @register="registerForm"/>
</BasicModal>
</template>
<script lang="ts" setup>
import {ref, computed, unref} from 'vue';
import {BasicModal, useModalInner} from '/@/components/Modal';
import {BasicForm, useForm} from '/@/components/Form/index';
import {formSchema} from '../NasaDataRecord.data';
import {saveOrUpdate} from '../NasaDataRecord.api';
// Emits声明
const emit = defineEmits(['register','success']);
const isUpdate = ref(true);
const isDetail = ref(false);
//表单配置
const [registerForm, {setProps,resetFields, setFieldsValue, validate}] = useForm({
//labelWidth: 150,
schemas: formSchema,
showActionButtonGroup: false,
baseColProps: {span: 24}
});
//表单赋值
const [registerModal, {setModalProps, closeModal}] = useModalInner(async (data) => {
//重置表单
await resetFields();
setModalProps({confirmLoading: false,showCancelBtn:!!data?.showFooter,showOkBtn:!!data?.showFooter});
isUpdate.value = !!data?.isUpdate;
isDetail.value = !!data?.showFooter;
if (unref(isUpdate)) {
//表单赋值
await setFieldsValue({
...data.record,
});
}
// 隐藏底部时禁用整个表单
setProps({ disabled: !data?.showFooter })
});
//设置标题
const title = computed(() => (!unref(isUpdate) ? '新增' : !unref(isDetail) ? '详情' : '编辑'));
//表单提交事件
async function handleSubmit(v) {
try {
let values = await validate();
setModalProps({confirmLoading: true});
//提交表单
await saveOrUpdate(values, isUpdate.value);
//关闭弹窗
closeModal();
//刷新列表
emit('success');
} finally {
setModalProps({confirmLoading: false});
}
}
</script>
<style lang="less" scoped>
/** 时间和数字输入框样式 */
:deep(.ant-input-number) {
width: 100%;
}
:deep(.ant-calendar-picker) {
width: 100%;
}
</style>

View File

@@ -1,71 +1,71 @@
package org.jeecg.modules.message.job; //package org.jeecg.modules.message.job;
//
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; //import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j; //import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.api.dto.message.MessageDTO; //import org.jeecg.common.api.dto.message.MessageDTO;
import org.jeecg.common.system.api.ISysBaseAPI; //import org.jeecg.common.system.api.ISysBaseAPI;
import org.jeecg.common.util.DateUtils; //import org.jeecg.common.util.DateUtils;
import org.jeecg.modules.message.entity.SysMessage; //import org.jeecg.modules.message.entity.SysMessage;
import org.jeecg.modules.message.handle.enums.SendMsgStatusEnum; //import org.jeecg.modules.message.handle.enums.SendMsgStatusEnum;
import org.jeecg.modules.message.service.ISysMessageService; //import org.jeecg.modules.message.service.ISysMessageService;
import org.quartz.Job; //import org.quartz.Job;
import org.quartz.JobExecutionContext; //import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException; //import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired; //import org.springframework.beans.factory.annotation.Autowired;
//
import java.util.List; //import java.util.List;
//
/** ///**
* 发送消息任务 // * 发送消息任务
* // *
* @author: jeecg-boot // * @author: jeecg-boot
*/ // */
//
@Slf4j //@Slf4j
public class SendMsgJob implements Job { //public class SendMsgJob implements Job {
//
@Autowired // @Autowired
private ISysMessageService sysMessageService; // private ISysMessageService sysMessageService;
//
@Autowired // @Autowired
private ISysBaseAPI sysBaseAPI; // private ISysBaseAPI sysBaseAPI;
//
@Override // @Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { // public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
//
log.info(String.format(" Jeecg-Boot 发送消息任务 SendMsgJob ! 时间:" + DateUtils.getTimestamp())); // log.info(String.format(" Jeecg-Boot 发送消息任务 SendMsgJob ! 时间:" + DateUtils.getTimestamp()));
//
// 1.读取消息中心数据,只查询未发送的和发送失败不超过次数的 // // 1.读取消息中心数据,只查询未发送的和发送失败不超过次数的
QueryWrapper<SysMessage> queryWrapper = new QueryWrapper<SysMessage>(); // QueryWrapper<SysMessage> queryWrapper = new QueryWrapper<SysMessage>();
queryWrapper.eq("es_send_status", SendMsgStatusEnum.WAIT.getCode()) // queryWrapper.eq("es_send_status", SendMsgStatusEnum.WAIT.getCode())
.or(i -> i.eq("es_send_status", SendMsgStatusEnum.FAIL.getCode()).lt("es_send_num", 6)); // .or(i -> i.eq("es_send_status", SendMsgStatusEnum.FAIL.getCode()).lt("es_send_num", 6));
List<SysMessage> sysMessages = sysMessageService.list(queryWrapper); // List<SysMessage> sysMessages = sysMessageService.list(queryWrapper);
System.out.println(sysMessages); // System.out.println(sysMessages);
// 2.根据不同的类型走不通的发送实现类 // // 2.根据不同的类型走不通的发送实现类
for (SysMessage sysMessage : sysMessages) { // for (SysMessage sysMessage : sysMessages) {
//update-begin-author:taoyan date:2022-7-8 for: 模板消息发送测试调用方法修改 // //update-begin-author:taoyan date:2022-7-8 for: 模板消息发送测试调用方法修改
Integer sendNum = sysMessage.getEsSendNum(); // Integer sendNum = sysMessage.getEsSendNum();
try { // try {
MessageDTO md = new MessageDTO(); // MessageDTO md = new MessageDTO();
md.setTitle(sysMessage.getEsTitle()); // md.setTitle(sysMessage.getEsTitle());
md.setContent(sysMessage.getEsContent()); // md.setContent(sysMessage.getEsContent());
md.setToUser(sysMessage.getEsReceiver()); // md.setToUser(sysMessage.getEsReceiver());
md.setType(sysMessage.getEsType()); // md.setType(sysMessage.getEsType());
md.setToAll(false); // md.setToAll(false);
sysBaseAPI.sendTemplateMessage(md); // sysBaseAPI.sendTemplateMessage(md);
//发送消息成功 // //发送消息成功
sysMessage.setEsSendStatus(SendMsgStatusEnum.SUCCESS.getCode()); // sysMessage.setEsSendStatus(SendMsgStatusEnum.SUCCESS.getCode());
//update-end-author:taoyan date:2022-7-8 for: 模板消息发送测试调用方法修改 // //update-end-author:taoyan date:2022-7-8 for: 模板消息发送测试调用方法修改
} catch (Exception e) { // } catch (Exception e) {
e.printStackTrace(); // e.printStackTrace();
// 发送消息出现异常 // // 发送消息出现异常
sysMessage.setEsSendStatus(SendMsgStatusEnum.FAIL.getCode()); // sysMessage.setEsSendStatus(SendMsgStatusEnum.FAIL.getCode());
} // }
sysMessage.setEsSendNum(++sendNum); // sysMessage.setEsSendNum(++sendNum);
// 发送结果回写到数据库 // // 发送结果回写到数据库
sysMessageService.updateById(sysMessage); // sysMessageService.updateById(sysMessage);
} // }
//
} // }
//
} //}

View File

@@ -1,292 +0,0 @@
package org.jeecg.modules.quartz.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.constant.SymbolConstant;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.ImportExcelUtil;
import org.jeecg.modules.quartz.entity.QuartzJob;
import org.jeecg.modules.quartz.service.IQuartzJobService;
import org.jeecgframework.poi.excel.ExcelImportUtil;
import org.jeecgframework.poi.excel.def.NormalExcelConstants;
import org.jeecgframework.poi.excel.entity.ExportParams;
import org.jeecgframework.poi.excel.entity.ImportParams;
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
/**
* @Description: 定时任务在线管理
* @Author: jeecg-boot
* @Date: 2019-01-02
* @Version:V1.0
*/
@RestController
@RequestMapping("/sys/quartzJob")
@Slf4j
@Tag(name = "定时任务接口")
public class QuartzJobController {
@Autowired
private IQuartzJobService quartzJobService;
@Autowired
private Scheduler scheduler;
/**
* 分页列表查询
*
* @param quartzJob
* @param pageNo
* @param pageSize
* @param req
* @return
*/
@RequestMapping(value = "/list", method = RequestMethod.GET)
public Result<?> queryPageList(QuartzJob quartzJob, @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize, HttpServletRequest req) {
QueryWrapper<QuartzJob> queryWrapper = QueryGenerator.initQueryWrapper(quartzJob, req.getParameterMap());
Page<QuartzJob> page = new Page<QuartzJob>(pageNo, pageSize);
IPage<QuartzJob> pageList = quartzJobService.page(page, queryWrapper);
return Result.ok(pageList);
}
/**
* 添加定时任务
*
* @param quartzJob
* @return
*/
//@RequiresRoles("admin")
@RequiresPermissions("system:quartzJob:add")
@RequestMapping(value = "/add", method = RequestMethod.POST)
public Result<?> add(@RequestBody QuartzJob quartzJob) {
quartzJobService.saveAndScheduleJob(quartzJob);
return Result.ok("创建定时任务成功");
}
/**
* 更新定时任务
*
* @param quartzJob
* @return
*/
//@RequiresRoles("admin")
@RequiresPermissions("system:quartzJob:edit")
@RequestMapping(value = "/edit", method = {RequestMethod.PUT, RequestMethod.POST})
public Result<?> eidt(@RequestBody QuartzJob quartzJob) {
try {
quartzJobService.editAndScheduleJob(quartzJob);
} catch (SchedulerException e) {
log.error(e.getMessage(), e);
return Result.error("更新定时任务失败!");
}
return Result.ok("更新定时任务成功!");
}
/**
* 通过id删除
*
* @param id
* @return
*/
//@RequiresRoles("admin")
@RequiresPermissions("system:quartzJob:delete")
@RequestMapping(value = "/delete", method = RequestMethod.DELETE)
public Result<?> delete(@RequestParam(name = "id", required = true) String id) {
QuartzJob quartzJob = quartzJobService.getById(id);
if (quartzJob == null) {
return Result.error("未找到对应实体");
}
quartzJobService.deleteAndStopJob(quartzJob);
return Result.ok("删除成功!");
}
/**
* 批量删除
*
* @param ids
* @return
*/
//@RequiresRoles("admin")
@RequiresPermissions("system:quartzJob:deleteBatch")
@RequestMapping(value = "/deleteBatch", method = RequestMethod.DELETE)
public Result<?> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
if (ids == null || "".equals(ids.trim())) {
return Result.error("参数不识别!");
}
for (String id : Arrays.asList(ids.split(SymbolConstant.COMMA))) {
QuartzJob job = quartzJobService.getById(id);
quartzJobService.deleteAndStopJob(job);
}
return Result.ok("删除定时任务成功!");
}
/**
* 暂停定时任务
*
* @param id
* @return
*/
//@RequiresRoles("admin")
@RequiresPermissions("system:quartzJob:pause")
@GetMapping(value = "/pause")
@Operation(summary = "停止定时任务")
public Result<Object> pauseJob(@RequestParam(name = "id") String id) {
QuartzJob job = quartzJobService.getById(id);
if (job == null) {
return Result.error("定时任务不存在!");
}
quartzJobService.pause(job);
return Result.ok("停止定时任务成功");
}
/**
* 启动定时任务
*
* @param id
* @return
*/
//@RequiresRoles("admin")
@RequiresPermissions("system:quartzJob:resume")
@GetMapping(value = "/resume")
@Operation(summary = "启动定时任务")
public Result<Object> resumeJob(@RequestParam(name = "id") String id) {
QuartzJob job = quartzJobService.getById(id);
if (job == null) {
return Result.error("定时任务不存在!");
}
quartzJobService.resumeJob(job);
//scheduler.resumeJob(JobKey.jobKey(job.getJobClassName().trim()));
return Result.ok("启动定时任务成功");
}
/**
* 通过id查询
*
* @param id
* @return
*/
@RequestMapping(value = "/queryById", method = RequestMethod.GET)
public Result<?> queryById(@RequestParam(name = "id", required = true) String id) {
QuartzJob quartzJob = quartzJobService.getById(id);
return Result.ok(quartzJob);
}
/**
* 导出excel
*
* @param request
* @param quartzJob
*/
@RequestMapping(value = "/exportXls")
public ModelAndView exportXls(HttpServletRequest request, QuartzJob quartzJob) {
// Step.1 组装查询条件
QueryWrapper<QuartzJob> queryWrapper = QueryGenerator.initQueryWrapper(quartzJob, request.getParameterMap());
// Step.2 AutoPoi 导出Excel
ModelAndView mv = new ModelAndView(new JeecgEntityExcelView());
List<QuartzJob> pageList = quartzJobService.list(queryWrapper);
// 导出文件名称
mv.addObject(NormalExcelConstants.FILE_NAME, "定时任务列表");
mv.addObject(NormalExcelConstants.CLASS, QuartzJob.class);
//获取当前登录用户
//update-begin---author:wangshuai ---date:20211227 for[JTC-116]导出人写死了------------
LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("定时任务列表数据", "导出人:" + user.getRealname(), "导出信息"));
//update-end---author:wangshuai ---date:20211227 for[JTC-116]导出人写死了------------
mv.addObject(NormalExcelConstants.DATA_LIST, pageList);
return mv;
}
/**
* 通过excel导入数据
*
* @param request
* @param response
* @return
*/
@RequestMapping(value = "/importExcel", method = RequestMethod.POST)
public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) throws IOException {
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
// 错误信息
List<String> errorMessage = new ArrayList<>();
int successLines = 0, errorLines = 0;
for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) {
// 获取上传文件对象
MultipartFile file = entity.getValue();
ImportParams params = new ImportParams();
params.setTitleRows(2);
params.setHeadRows(1);
params.setNeedSave(true);
try {
List<QuartzJob> listQuartzJobs = ExcelImportUtil.importExcel(file.getInputStream(), QuartzJob.class, params);
//add-begin-author:taoyan date:20210909 for:导入定时任务,并不会被启动和调度,需要手动点击启动,才会加入调度任务中 #2986
for (QuartzJob job : listQuartzJobs) {
job.setStatus(CommonConstant.STATUS_DISABLE);
}
List<String> list = ImportExcelUtil.importDateSave(listQuartzJobs, IQuartzJobService.class, errorMessage, CommonConstant.SQL_INDEX_UNIQ_JOB_CLASS_NAME);
//add-end-author:taoyan date:20210909 for:导入定时任务,并不会被启动和调度,需要手动点击启动,才会加入调度任务中 #2986
errorLines += list.size();
successLines += (listQuartzJobs.size() - errorLines);
} catch (Exception e) {
log.error(e.getMessage(), e);
return Result.error("文件导入失败!");
} finally {
try {
file.getInputStream().close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return ImportExcelUtil.imporReturnRes(errorLines, successLines, errorMessage);
}
/**
* 立即执行
*
* @param id
* @return
*/
//@RequiresRoles("admin")
@RequiresPermissions("system:quartzJob:execute")
@GetMapping("/execute")
public Result<?> execute(@RequestParam(name = "id", required = true) String id) {
QuartzJob quartzJob = quartzJobService.getById(id);
if (quartzJob == null) {
return Result.error("未找到对应实体");
}
try {
quartzJobService.execute(quartzJob);
} catch (Exception e) {
//e.printStackTrace();
log.info("定时任务 立即执行失败>>" + e.getMessage());
return Result.error("执行失败!");
}
return Result.ok("执行成功!");
}
}

View File

@@ -1,81 +0,0 @@
package org.jeecg.modules.quartz.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import org.jeecg.common.aspect.annotation.Dict;
import org.jeecgframework.poi.excel.annotation.Excel;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
/**
* @Description: 定时任务在线管理
* @Author: jeecg-boot
* @Date: 2019-01-02
* @Version: V1.0
*/
@Data
@TableName("sys_quartz_job")
public class QuartzJob implements Serializable {
private static final long serialVersionUID = 1L;
/**
* id
*/
@TableId(type = IdType.ASSIGN_ID)
private java.lang.String id;
/**
* 创建人
*/
private java.lang.String createBy;
/**
* 创建时间
*/
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private java.util.Date createTime;
/**
* 删除状态
*/
private java.lang.Integer delFlag;
/**
* 修改人
*/
private java.lang.String updateBy;
/**
* 修改时间
*/
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private java.util.Date updateTime;
/**
* 任务类名
*/
@Excel(name = "任务类名", width = 40)
private java.lang.String jobClassName;
/**
* cron表达式
*/
@Excel(name = "cron表达式", width = 30)
private java.lang.String cronExpression;
/**
* 参数
*/
@Excel(name = "参数", width = 15)
private java.lang.String parameter;
/**
* 描述
*/
@Excel(name = "描述", width = 40)
private java.lang.String description;
/**
* 状态 0正常 -1停止
*/
@Excel(name = "状态", width = 15, dicCode = "quartz_status")
@Dict(dicCode = "quartz_status")
private java.lang.Integer status;
}

View File

@@ -1,33 +0,0 @@
package org.jeecg.modules.quartz.job;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.util.DateUtils;
import org.quartz.*;
/**
* @Description: 同步定时任务测试
* <p>
* 此处的同步是指 当定时任务的执行时间大于任务的时间间隔时
* 会等待第一个任务执行完成才会走第二个任务
* @author: taoyan
* @date: 2020年06月19日
*/
@PersistJobDataAfterExecution
@DisallowConcurrentExecution
@Slf4j
public class AsyncJob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
log.info(" --- 同步任务调度开始 --- ");
try {
//此处模拟任务执行时间 5秒 任务表达式配置为每秒执行一次0/1 * * * * ? *
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//测试发现 每5秒执行一次
log.info(" --- 执行完毕,时间:" + DateUtils.now() + "---");
}
}

View File

@@ -1,22 +0,0 @@
package org.jeecg.modules.quartz.job;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.util.DateUtils;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
/**
* 示例不带参定时任务
*
* @Author Scott
*/
@Slf4j
public class SampleJob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
log.info(" Job Execution key" + jobExecutionContext.getJobDetail().getKey());
log.info(String.format(" Jeecg-Boot 普通定时任务 SampleJob ! 时间:" + DateUtils.getTimestamp()));
}
}

View File

@@ -1,31 +0,0 @@
package org.jeecg.modules.quartz.job;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.util.DateUtils;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
/**
* 示例带参定时任务
*
* @Author Scott
*/
@Slf4j
public class SampleParamJob implements Job {
/**
* 若参数变量名修改 QuartzJobController中也需对应修改
*/
private String parameter;
public void setParameter(String parameter) {
this.parameter = parameter;
}
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
log.info(" Job Execution key" + jobExecutionContext.getJobDetail().getKey());
log.info(String.format("welcome %s! Jeecg-Boot 带参数定时任务 SampleParamJob ! 时间:" + DateUtils.now(), this.parameter));
}
}

View File

@@ -1,25 +0,0 @@
package org.jeecg.modules.quartz.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
import org.jeecg.modules.quartz.entity.QuartzJob;
import java.util.List;
/**
* @Description: 定时任务在线管理
* @Author: jeecg-boot
* @Date: 2019-01-02
* @Version: V1.0
*/
public interface QuartzJobMapper extends BaseMapper<QuartzJob> {
/**
* 根据jobClassName查询
*
* @param jobClassName 任务类名
* @return
*/
public List<QuartzJob> findByJobClassName(@Param("jobClassName") String jobClassName);
}

View File

@@ -1,9 +0,0 @@
<?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="org.jeecg.modules.quartz.mapper.QuartzJobMapper">
<!-- 根据jobClassName查询 -->
<select id="findByJobClassName" resultType="org.jeecg.modules.quartz.entity.QuartzJob">
select * from sys_quartz_job where job_class_name = #{jobClassName}
</select>
</mapper>

View File

@@ -1,73 +0,0 @@
package org.jeecg.modules.quartz.service;
import com.baomidou.mybatisplus.extension.service.IService;
import org.jeecg.modules.quartz.entity.QuartzJob;
import org.quartz.SchedulerException;
import java.util.List;
/**
* @Description: 定时任务在线管理
* @Author: jeecg-boot
* @Date: 2019-04-28
* @Version: V1.1
*/
public interface IQuartzJobService extends IService<QuartzJob> {
/**
* 通过类名寻找定时任务
*
* @param jobClassName 类名
* @return List<QuartzJob>
*/
List<QuartzJob> findByJobClassName(String jobClassName);
/**
* 保存定时任务
*
* @param quartzJob
* @return boolean
*/
boolean saveAndScheduleJob(QuartzJob quartzJob);
/**
* 编辑定时任务
*
* @param quartzJob
* @return boolean
* @throws SchedulerException
*/
boolean editAndScheduleJob(QuartzJob quartzJob) throws SchedulerException;
/**
* 删除定时任务
*
* @param quartzJob
* @return boolean
*/
boolean deleteAndStopJob(QuartzJob quartzJob);
/**
* 恢复定时任务
*
* @param quartzJob
* @return
*/
boolean resumeJob(QuartzJob quartzJob);
/**
* 执行定时任务
*
* @param quartzJob
* @throws Exception
*/
void execute(QuartzJob quartzJob) throws Exception;
/**
* 暂停任务
*
* @param quartzJob
* @throws SchedulerException
*/
void pause(QuartzJob quartzJob);
}

View File

@@ -1,184 +0,0 @@
package org.jeecg.modules.quartz.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.util.DateUtils;
import org.jeecg.modules.quartz.entity.QuartzJob;
import org.jeecg.modules.quartz.mapper.QuartzJobMapper;
import org.jeecg.modules.quartz.service.IQuartzJobService;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
import java.util.List;
/**
* @Description: 定时任务在线管理
* @Author: jeecg-boot
* @Date: 2019-04-28
* @Version: V1.1
*/
@Slf4j
@Service
public class QuartzJobServiceImpl extends ServiceImpl<QuartzJobMapper, QuartzJob> implements IQuartzJobService {
@Autowired
private QuartzJobMapper quartzJobMapper;
@Autowired
private Scheduler scheduler;
/**
* 立即执行的任务分组
*/
private static final String JOB_TEST_GROUP = "test_group";
@Override
public List<QuartzJob> findByJobClassName(String jobClassName) {
return quartzJobMapper.findByJobClassName(jobClassName);
}
/**
* 保存&启动定时任务
*/
@Override
@Transactional(rollbackFor = JeecgBootException.class)
public boolean saveAndScheduleJob(QuartzJob quartzJob) {
// DB设置修改
quartzJob.setDelFlag(CommonConstant.DEL_FLAG_0);
boolean success = this.save(quartzJob);
if (success) {
if (CommonConstant.STATUS_NORMAL.equals(quartzJob.getStatus())) {
// 定时器添加
this.schedulerAdd(quartzJob.getId(), quartzJob.getJobClassName().trim(), quartzJob.getCronExpression().trim(), quartzJob.getParameter());
}
}
return success;
}
/**
* 恢复定时任务
*/
@Override
@Transactional(rollbackFor = JeecgBootException.class)
public boolean resumeJob(QuartzJob quartzJob) {
schedulerDelete(quartzJob.getId());
schedulerAdd(quartzJob.getId(), quartzJob.getJobClassName().trim(), quartzJob.getCronExpression().trim(), quartzJob.getParameter());
quartzJob.setStatus(CommonConstant.STATUS_NORMAL);
return this.updateById(quartzJob);
}
/**
* 编辑&启停定时任务
*
* @throws SchedulerException
*/
@Override
@Transactional(rollbackFor = JeecgBootException.class)
public boolean editAndScheduleJob(QuartzJob quartzJob) throws SchedulerException {
if (CommonConstant.STATUS_NORMAL.equals(quartzJob.getStatus())) {
schedulerDelete(quartzJob.getId());
schedulerAdd(quartzJob.getId(), quartzJob.getJobClassName().trim(), quartzJob.getCronExpression().trim(), quartzJob.getParameter());
} else {
scheduler.pauseJob(JobKey.jobKey(quartzJob.getId()));
}
return this.updateById(quartzJob);
}
/**
* 删除&停止删除定时任务
*/
@Override
@Transactional(rollbackFor = JeecgBootException.class)
public boolean deleteAndStopJob(QuartzJob job) {
schedulerDelete(job.getId());
boolean ok = this.removeById(job.getId());
return ok;
}
@Override
public void execute(QuartzJob quartzJob) throws Exception {
String jobName = quartzJob.getJobClassName().trim();
Date startDate = new Date();
String ymd = DateUtils.date2Str(startDate, DateUtils.yyyymmddhhmmss.get());
String identity = jobName + ymd;
//3秒后执行 只执行一次
// update-begin--author:sunjianlei ---- date:20210511--- for定时任务立即执行延迟3秒改成0.1秒-------
startDate.setTime(startDate.getTime() + 100L);
// update-end--author:sunjianlei ---- date:20210511--- for定时任务立即执行延迟3秒改成0.1秒-------
// 定义一个Trigger
SimpleTrigger trigger = (SimpleTrigger) TriggerBuilder.newTrigger()
.withIdentity(identity, JOB_TEST_GROUP)
.startAt(startDate)
.build();
// 构建job信息
JobDetail jobDetail = JobBuilder.newJob(getClass(jobName).getClass()).withIdentity(identity).usingJobData("parameter", quartzJob.getParameter()).build();
// 将trigger和 jobDetail 加入这个调度
scheduler.scheduleJob(jobDetail, trigger);
// 启动scheduler
scheduler.start();
}
@Override
@Transactional(rollbackFor = JeecgBootException.class)
public void pause(QuartzJob quartzJob) {
schedulerDelete(quartzJob.getId());
quartzJob.setStatus(CommonConstant.STATUS_DISABLE);
this.updateById(quartzJob);
}
/**
* 添加定时任务
*
* @param jobClassName
* @param cronExpression
* @param parameter
*/
private void schedulerAdd(String id, String jobClassName, String cronExpression, String parameter) {
try {
// 启动调度器
scheduler.start();
// 构建job信息
JobDetail jobDetail = JobBuilder.newJob(getClass(jobClassName).getClass()).withIdentity(id).usingJobData("parameter", parameter).build();
// 表达式调度构建器(即任务执行的时间)
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
// 按新的cronExpression表达式构建一个新的trigger
CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(id).withSchedule(scheduleBuilder).build();
scheduler.scheduleJob(jobDetail, trigger);
} catch (SchedulerException e) {
throw new JeecgBootException("创建定时任务失败", e);
} catch (RuntimeException e) {
throw new JeecgBootException(e.getMessage(), e);
} catch (Exception e) {
throw new JeecgBootException("后台找不到该类名:" + jobClassName, e);
}
}
/**
* 删除定时任务
*
* @param id
*/
private void schedulerDelete(String id) {
try {
scheduler.pauseTrigger(TriggerKey.triggerKey(id));
scheduler.unscheduleJob(TriggerKey.triggerKey(id));
scheduler.deleteJob(JobKey.jobKey(id));
} catch (Exception e) {
log.error(e.getMessage(), e);
throw new JeecgBootException("删除定时任务失败");
}
}
private static Job getClass(String classname) throws Exception {
Class<?> class1 = Class.forName(classname);
return (Job) class1.newInstance();
}
}

View File

@@ -46,6 +46,7 @@ import java.util.*;
@Tag(name = "用户登录") @Tag(name = "用户登录")
@Slf4j @Slf4j
public class LoginController { public class LoginController {
private final String BASE_CHECK_CODES = "qwertyuiplkjhgfdsazxcvbnmQWERTYUPLKJHGFDSAZXCVBNM1234567890";
@Autowired @Autowired
private ISysUserService sysUserService; private ISysUserService sysUserService;
@Autowired @Autowired
@@ -65,8 +66,6 @@ public class LoginController {
@Autowired @Autowired
private JeecgBaseConfig jeecgBaseConfig; private JeecgBaseConfig jeecgBaseConfig;
private final String BASE_CHECK_CODES = "qwertyuiplkjhgfdsazxcvbnmQWERTYUPLKJHGFDSAZXCVBNM1234567890";
@Operation(summary = "登录接口") @Operation(summary = "登录接口")
@RequestMapping(value = "/login", method = RequestMethod.POST) @RequestMapping(value = "/login", method = RequestMethod.POST)
public Result<JSONObject> login(@RequestBody SysLoginModel sysLoginModel, HttpServletRequest request) { public Result<JSONObject> login(@RequestBody SysLoginModel sysLoginModel, HttpServletRequest request) {
@@ -74,7 +73,8 @@ public class LoginController {
String username = sysLoginModel.getUsername(); String username = sysLoginModel.getUsername();
String password = sysLoginModel.getPassword(); String password = sysLoginModel.getPassword();
if (isLoginFailOvertimes(username)) { if (isLoginFailOvertimes(username)) {
return result.error500("该用户登录失败次数过多请于10分钟后再次登录"); long expire = redisUtil.getExpire(CommonConstant.LOGIN_FAIL + username);
return result.error500("该用户登录失败次数过多,请于" + (expire / 60) + 1 + "分钟后再次登录!");
} }
// step.1 验证码check // step.1 验证码check