1111
This commit is contained in:
parent
92142ef2d0
commit
146195e3fb
@ -53,6 +53,18 @@ public class BaseCalendarEventController extends BaseController
|
||||
return success(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步中国节假日
|
||||
* @author PQZ
|
||||
* @date 17:18 2025/11/3
|
||||
* @return com.ruoyi.common.core.domain.AjaxResult
|
||||
**/
|
||||
@GetMapping("/syncEvent")
|
||||
public AjaxResult syncEvent() {
|
||||
baseCalendarEventService.syncEvent();
|
||||
return success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出节日列表
|
||||
*/
|
||||
|
||||
@ -15,4 +15,6 @@ import com.ruoyi.base.domain.BaseCalendarEvent;
|
||||
public interface IBaseCalendarEventService extends IService<BaseCalendarEvent>
|
||||
{
|
||||
IPage<BaseCalendarEvent> queryListPage(BaseCalendarEvent pageReqVO, Page<BaseCalendarEvent> page);
|
||||
|
||||
void syncEvent();
|
||||
}
|
||||
|
||||
@ -1,14 +1,29 @@
|
||||
package com.ruoyi.base.service.impl;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Year;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.ruoyi.base.mapper.BaseCalendarEventMapper;
|
||||
import com.ruoyi.base.domain.BaseCalendarEvent;
|
||||
import com.ruoyi.base.service.IBaseCalendarEventService;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
/**
|
||||
* 节日Service业务层处理
|
||||
@ -17,13 +32,60 @@ import com.ruoyi.base.service.IBaseCalendarEventService;
|
||||
* @date 2025-10-31
|
||||
*/
|
||||
@Service
|
||||
public class BaseCalendarEventServiceImpl extends ServiceImpl<BaseCalendarEventMapper,BaseCalendarEvent> implements IBaseCalendarEventService
|
||||
{
|
||||
public class BaseCalendarEventServiceImpl extends ServiceImpl<BaseCalendarEventMapper, BaseCalendarEvent> implements IBaseCalendarEventService {
|
||||
@Autowired
|
||||
private BaseCalendarEventMapper baseCalendarEventMapper;
|
||||
private final RestTemplate restTemplate = new RestTemplate();
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
@Override
|
||||
public IPage<BaseCalendarEvent> queryListPage(BaseCalendarEvent pageReqVO, Page<BaseCalendarEvent> page) {
|
||||
return baseCalendarEventMapper.queryListPage(pageReqVO, page);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void syncEvent() {
|
||||
String apiKey = "55bc9d05a05e5e1c0183f7ab380707d8";
|
||||
String baseUrl = "https://apis.tianapi.com/jiejiari/index";
|
||||
String date = "2025";
|
||||
String type = "1";
|
||||
|
||||
try {
|
||||
// 构建请求URL
|
||||
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(baseUrl)
|
||||
.queryParam("key", apiKey)
|
||||
.queryParam("date", date)
|
||||
.queryParam("type", type);
|
||||
|
||||
// 发送GET请求
|
||||
String response = restTemplate.getForObject(builder.toUriString(), String.class);
|
||||
|
||||
// 解析响应JSON
|
||||
if (response != null) {
|
||||
Map<String, Object> resultMap = objectMapper.readValue(response, Map.class);
|
||||
Integer code = (Integer) resultMap.get("code");
|
||||
|
||||
// 检查请求是否成功
|
||||
if (code != null && code == 200) {
|
||||
Map<String, Object> newsMap = (Map<String, Object>) resultMap.get("result");
|
||||
List<Map<String, Object>> dataList = (List<Map<String, Object>>) newsMap.get("list");
|
||||
|
||||
// 输出数据到控制台
|
||||
System.out.println("获取到 " + dataList.size() + " 条节假日数据:");
|
||||
for (Map<String, Object> data : dataList) {
|
||||
System.out.println("日期: " + data.get("date") +
|
||||
", 名称: " + data.get("name") +
|
||||
", 类型: " + data.get("type"));
|
||||
}
|
||||
} else {
|
||||
System.err.println("获取节假日数据失败,错误码: " + code +
|
||||
", 错误信息: " + resultMap.get("msg"));
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -44,7 +44,6 @@ public class BaseCalendarServiceImpl extends ServiceImpl<BaseCalendarMapper, Bas
|
||||
**/
|
||||
@Override
|
||||
public void generateCalendar() {
|
||||
|
||||
// 获取当前年份
|
||||
int currentYear = LocalDate.now().getYear();
|
||||
// 从当前年份的1月1日开始计算
|
||||
@ -62,13 +61,14 @@ public class BaseCalendarServiceImpl extends ServiceImpl<BaseCalendarMapper, Bas
|
||||
calendar.setDay((long) date.getDayOfMonth());
|
||||
calendar.setWeek((long) date.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR));
|
||||
calendar.setWeekday((long) date.getDayOfWeek().getValue());
|
||||
|
||||
// 使用Hutool计算农历日期
|
||||
calendar.setLunarDate(calculateLunarDate(date));
|
||||
|
||||
// 默认工作状态为空(正常工作日)
|
||||
calendar.setWorkStatus("");
|
||||
|
||||
// 设置工作状态:周六(6)和周日(7)设置为"休"
|
||||
if (date.getDayOfWeek().getValue() == 6 || date.getDayOfWeek().getValue() == 7) {
|
||||
calendar.setWorkStatus("休");
|
||||
} else {
|
||||
calendar.setWorkStatus("");
|
||||
}
|
||||
calendarList.add(calendar);
|
||||
}
|
||||
//批量保存到数据库
|
||||
|
||||
@ -163,6 +163,11 @@ dify:
|
||||
# key: app-ahgDwrLi8KQ6V0aEKKwT6Io7
|
||||
# url: http://10.19.128.77/v1
|
||||
|
||||
# 登录相关配置
|
||||
login:
|
||||
# 是否限制单用户登录
|
||||
single: true
|
||||
|
||||
|
||||
# Python环境配置
|
||||
python:
|
||||
|
||||
@ -6,6 +6,7 @@ import com.alibaba.fastjson2.JSONObject;
|
||||
import com.ruoyi.common.utils.uuid.IdUtils;
|
||||
import com.ruoyi.system.mapper.SysUserMapper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
@ -58,6 +59,9 @@ public class SysLoginService
|
||||
@Autowired
|
||||
private ISysConfigService configService;
|
||||
|
||||
@Value("${login.single}")
|
||||
private boolean isSingle;
|
||||
|
||||
/**
|
||||
* 登录验证
|
||||
*
|
||||
@ -102,8 +106,8 @@ public class SysLoginService
|
||||
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
|
||||
LoginUser loginUser = (LoginUser) authentication.getPrincipal();
|
||||
recordLoginInfo(loginUser.getUserId());
|
||||
// 生成token
|
||||
return tokenService.createToken(loginUser);
|
||||
String token = tokenService.createToken(loginUser);
|
||||
return token;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -8,6 +8,13 @@ export function listEvent(query) {
|
||||
params: query
|
||||
})
|
||||
}
|
||||
// 生成日历
|
||||
export function syncEvent() {
|
||||
return request({
|
||||
url: '/base/event/syncEvent',
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
|
||||
// 查询节日详细
|
||||
export function getEvent(id) {
|
||||
|
||||
@ -6,6 +6,7 @@ import 'nprogress/nprogress.css'
|
||||
import { getToken } from '@/utils/auth'
|
||||
import { isPathMatch } from '@/utils/validate'
|
||||
import { isRelogin } from '@/utils/request'
|
||||
import watermark from '@/utils/watermark' // 引入水印工具
|
||||
|
||||
NProgress.configure({ showSpinner: false })
|
||||
|
||||
@ -31,6 +32,21 @@ router.beforeEach((to, from, next) => {
|
||||
// 判断当前用户是否已拉取完user_info信息
|
||||
store.dispatch('GetInfo').then(() => {
|
||||
isRelogin.show = false
|
||||
// 清理可能存在的旧水印
|
||||
watermark.remove()
|
||||
|
||||
// 设置新水印
|
||||
const currentUser = store.getters.name || '未知用户'
|
||||
const currentDate = new Date().toLocaleDateString()
|
||||
watermark.set({
|
||||
text: `${currentUser}\n${currentDate}`,
|
||||
color: 'rgba(180, 180, 180, 0.3)',
|
||||
fontSize: 16,
|
||||
rotate: -15,
|
||||
density: 0.6,
|
||||
zIndex: 9999
|
||||
})
|
||||
|
||||
store.dispatch('GenerateRoutes').then(accessRoutes => {
|
||||
// 根据roles权限生成可访问的路由表
|
||||
router.addRoutes(accessRoutes) // 动态添加可访问路由表
|
||||
@ -43,6 +59,20 @@ router.beforeEach((to, from, next) => {
|
||||
})
|
||||
})
|
||||
} else {
|
||||
// 清理可能存在的旧水印
|
||||
watermark.remove()
|
||||
|
||||
// 设置新水印
|
||||
const currentUser = store.getters.name || '未知用户'
|
||||
const currentDate = new Date().toLocaleDateString()
|
||||
watermark.set({
|
||||
text: `${currentUser}\n${currentDate}`,
|
||||
color: 'rgba(180, 180, 180, 0.3)',
|
||||
fontSize: 16,
|
||||
rotate: -15,
|
||||
density: 0.6,
|
||||
zIndex: 9999
|
||||
})
|
||||
next()
|
||||
}
|
||||
}
|
||||
|
||||
74
dl_vue/src/utils/watermark.js
Normal file
74
dl_vue/src/utils/watermark.js
Normal file
@ -0,0 +1,74 @@
|
||||
// src/utils/watermark.js
|
||||
let watermarkDom = null // 水印DOM缓存
|
||||
|
||||
/**
|
||||
* 创建水印
|
||||
* @param {Object} options 水印配置
|
||||
* @param {String} options.text 水印文字(支持\n换行)
|
||||
* @param {String} options.color 文字颜色(默认rgba(180,180,180,0.3))
|
||||
* @param {Number} options.fontSize 字体大小(默认18px)
|
||||
* @param {Number} options.rotate 旋转角度(默认-15)
|
||||
* @param {Number} options.density 密度(0-1,默认0.3)
|
||||
* @param {Number} options.zIndex 层级(默认9999)
|
||||
*/
|
||||
function createWatermark(options = {}) {
|
||||
// 合并默认配置
|
||||
const {
|
||||
text = 'RuoYi 水印',
|
||||
color = 'rgba(180, 180, 180, 0.5)',
|
||||
fontSize = 10,
|
||||
rotate = -15,
|
||||
density = 0.6,
|
||||
zIndex = 9999
|
||||
} = options
|
||||
|
||||
// 移除已存在的水印
|
||||
if (watermarkDom) {
|
||||
document.body.removeChild(watermarkDom)
|
||||
}
|
||||
|
||||
// 创建水印容器
|
||||
watermarkDom = document.createElement('div')
|
||||
watermarkDom.style.position = 'fixed'
|
||||
watermarkDom.style.top = '0'
|
||||
watermarkDom.style.left = '0'
|
||||
watermarkDom.style.width = '100%'
|
||||
watermarkDom.style.height = '100%'
|
||||
watermarkDom.style.pointerEvents = 'none' // 不影响页面交互
|
||||
watermarkDom.style.zIndex = zIndex
|
||||
document.body.appendChild(watermarkDom)
|
||||
|
||||
// 生成Canvas水印图
|
||||
const canvas = document.createElement('canvas')
|
||||
const ctx = canvas.getContext('2d')
|
||||
// 计算单条水印大小(根据文字长度动态调整)
|
||||
const textArr = text.split('\n')
|
||||
const maxTextLength = Math.max(...textArr.map(t => t.length))
|
||||
canvas.width = maxTextLength * fontSize * 1.2 // 宽度适配文字,增加间距
|
||||
canvas.height = textArr.length * fontSize * 3.2 // 高度适配行数,增加间距
|
||||
// 绘制文字
|
||||
ctx.fillStyle = color
|
||||
ctx.font = `${fontSize}px SimHei, sans-serif`
|
||||
ctx.textAlign = 'center'
|
||||
ctx.textBaseline = 'middle'
|
||||
ctx.rotate((Math.PI / 180) * rotate) // 旋转
|
||||
// 多行文字绘制
|
||||
textArr.forEach((line, index) => {
|
||||
ctx.fillText(line, canvas.width / 2, canvas.height / 2 + (index - (textArr.length - 1) / 2) * fontSize * 1.5)
|
||||
})
|
||||
// 设置为背景图,重复平铺
|
||||
watermarkDom.style.backgroundImage = `url(${canvas.toDataURL('image/png')})`
|
||||
watermarkDom.style.backgroundSize = `${canvas.width / density}px ${canvas.height / density}px` // 调整密度控制逻辑
|
||||
}
|
||||
|
||||
export default {
|
||||
// 设置水印(创建或更新)
|
||||
set: (options) => createWatermark(options),
|
||||
// 移除水印
|
||||
remove: () => {
|
||||
if (watermarkDom && document.body.contains(watermarkDom)) {
|
||||
document.body.removeChild(watermarkDom)
|
||||
watermarkDom = null
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,10 +1,23 @@
|
||||
<template>
|
||||
|
||||
<div class="app-container">
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
size="mini"
|
||||
@click="generate"
|
||||
v-hasPermi="['base:calendar:add']"
|
||||
>日历同步</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-calendar v-model="currentDate" ref="calendar">
|
||||
<template slot="dateCell" slot-scope="{ date, data }">
|
||||
<div class="calendar-cell">
|
||||
<div class="calendar-date">{{ data.day.split('-')[2] }}</div>
|
||||
<div class="lunar-date">{{ getLunarDate(data.day) }}</div>
|
||||
<div v-if="getWorkStatus(data.day)" class="work-status">休</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-calendar>
|
||||
@ -12,23 +25,33 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listCalendar } from '@/api/base/calendar'
|
||||
import { listCalendar,generateCalendar } from '@/api/base/calendar'
|
||||
|
||||
export default {
|
||||
name: "CalendarView",
|
||||
name: 'CalendarView',
|
||||
data() {
|
||||
return {
|
||||
currentDate: new Date(),
|
||||
calendarData: []
|
||||
};
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.fetchCalendarData();
|
||||
watch: {
|
||||
// 更严谨的写法,直接复制粘贴代码的朋友记得把上方的1.删掉再使用
|
||||
currentDate(val, oldVal) {
|
||||
const year = val.getFullYear()
|
||||
const month = val.getMonth() + 1
|
||||
this.fetchCalendarData(year, month)
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
const year = this.currentDate.getFullYear()
|
||||
const month = this.currentDate.getMonth() + 1
|
||||
this.fetchCalendarData(year, month)
|
||||
},
|
||||
|
||||
methods: {
|
||||
fetchCalendarData() {
|
||||
const year = this.currentDate.getFullYear();
|
||||
const month = this.currentDate.getMonth() + 1;
|
||||
fetchCalendarData(year, month) {
|
||||
// 根据当前年月查询数据
|
||||
listCalendar({
|
||||
pageNum: 1,
|
||||
@ -36,32 +59,61 @@ export default {
|
||||
year: year,
|
||||
month: month
|
||||
}).then(response => {
|
||||
this.calendarData = response.data.records;
|
||||
console.log(this.calendarData)
|
||||
});
|
||||
this.calendarData = response.data.records
|
||||
})
|
||||
},
|
||||
generate(){
|
||||
generateCalendar().then(res => {
|
||||
this.$message.success("同步成功")
|
||||
})
|
||||
},
|
||||
|
||||
getLunarDate(dateStr) {
|
||||
// 查找对应日期的农历信息
|
||||
const date = new Date(dateStr);
|
||||
const year = date.getFullYear();
|
||||
const month = date.getMonth() + 1;
|
||||
const day = date.getDate();
|
||||
/**
|
||||
* 根据日期获取日历记录
|
||||
* @param {string} dateStr - 日期字符串
|
||||
* @returns {Object|null} 对应的日期记录
|
||||
*/
|
||||
getCalendarRecord(dateStr) {
|
||||
const date = new Date(dateStr)
|
||||
const year = date.getFullYear()
|
||||
const month = date.getMonth() + 1
|
||||
const day = date.getDate()
|
||||
|
||||
// 添加防御性检查
|
||||
if (!this.calendarData || this.calendarData.length === 0) {
|
||||
return null;
|
||||
return null
|
||||
}
|
||||
const record = this.calendarData.find(item =>
|
||||
|
||||
return this.calendarData.find(item =>
|
||||
item.year === year &&
|
||||
item.month === month &&
|
||||
item.day === day
|
||||
)
|
||||
return record ? record.lunarDate : null;
|
||||
) || null
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* 获取农历日期
|
||||
* @param {string} dateStr - 日期字符串
|
||||
* @returns {string|null} 农历日期
|
||||
*/
|
||||
getLunarDate(dateStr) {
|
||||
const record = this.getCalendarRecord(dateStr)
|
||||
return record ? record.lunarDate : null
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取工作状态
|
||||
* @param {string} dateStr - 日期字符串
|
||||
* @returns {boolean} 是否为休息日
|
||||
*/
|
||||
getWorkStatus(dateStr) {
|
||||
const record = this.getCalendarRecord(dateStr)
|
||||
return record ? record.workStatus : null
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@ -82,6 +134,13 @@ export default {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.work-status {
|
||||
font-size: 12px;
|
||||
color: #ef9e11;
|
||||
font-weight: bold;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.el-calendar-table .el-calendar-day:hover {
|
||||
background-color: #f2f8ff;
|
||||
}
|
||||
|
||||
@ -32,6 +32,15 @@
|
||||
</el-form>
|
||||
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
icon="el-icon-plus"
|
||||
size="mini"
|
||||
@click="eventSync"
|
||||
>同步</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="primary"
|
||||
@ -133,7 +142,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listEvent, getEvent, delEvent, addEvent, updateEvent } from "@/api/base/event";
|
||||
import { listEvent, getEvent,syncEvent, delEvent, addEvent, updateEvent } from "@/api/base/event";
|
||||
|
||||
export default {
|
||||
name: "Event",
|
||||
@ -176,6 +185,13 @@ export default {
|
||||
this.getList();
|
||||
},
|
||||
methods: {
|
||||
|
||||
eventSync(){
|
||||
syncEvent().then(res =>{
|
||||
this.$modal.msgSuccess("同步成功");
|
||||
})
|
||||
},
|
||||
|
||||
/** 查询节日列表 */
|
||||
getList() {
|
||||
this.loading = true;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user