修复日程提醒功能
This commit is contained in:
@@ -1 +1 @@
|
||||
{"pid":54204,"startedAt":1784192140605}
|
||||
{"pid":4264,"startedAt":1784510683025}
|
||||
@@ -22,6 +22,14 @@ export default defineConfig({
|
||||
},
|
||||
},
|
||||
server: {
|
||||
host: '127.0.0.1',
|
||||
port: 4001,
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: 'http://127.0.0.1:9000',
|
||||
changeOrigin: true,
|
||||
rewrite: (path) => path.replace(/^\/api/, ''),
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@@ -13,7 +13,8 @@ type ApiReminderController struct {
|
||||
}
|
||||
|
||||
// AckReminder GET /api/schedule/reminder/ack
|
||||
// 邮件/Bark 客户端访问此接口进行提醒确认
|
||||
// 邮件/Bark 客户端访问此接口进行提醒确认。
|
||||
// backend 与 platform 使用各自的提醒表,这里按 token 自动识别来源。
|
||||
func (c *ApiReminderController) AckReminder() {
|
||||
token := c.GetString("token")
|
||||
if token == "" {
|
||||
@@ -22,19 +23,101 @@ func (c *ApiReminderController) AckReminder() {
|
||||
return
|
||||
}
|
||||
|
||||
var reminder models.PlatformScheduleReminder
|
||||
err := models.Orm.QueryTable(new(models.PlatformScheduleReminder)).
|
||||
type reminderState struct {
|
||||
AckStatus int8
|
||||
ScheduleID uint64
|
||||
RemindStatus int8
|
||||
}
|
||||
|
||||
var state reminderState
|
||||
table := ""
|
||||
|
||||
var backendReminder models.BackendScheduleReminder
|
||||
if err := models.Orm.QueryTable(new(models.BackendScheduleReminder)).
|
||||
Filter("ack_token", token).
|
||||
Filter("is_deleted", 0).
|
||||
One(&reminder)
|
||||
if err != nil {
|
||||
One(&backendReminder); err == nil {
|
||||
state = reminderState{
|
||||
AckStatus: backendReminder.AckStatus,
|
||||
ScheduleID: backendReminder.ScheduleID,
|
||||
RemindStatus: backendReminder.RemindStatus,
|
||||
}
|
||||
table = "backend"
|
||||
} else {
|
||||
var platformReminder models.PlatformScheduleReminder
|
||||
if err := models.Orm.QueryTable(new(models.PlatformScheduleReminder)).
|
||||
Filter("ack_token", token).
|
||||
Filter("is_deleted", 0).
|
||||
One(&platformReminder); err != nil {
|
||||
c.Ctx.Output.SetStatus(404)
|
||||
_ = c.Ctx.Output.Body([]byte("Error: reminder task not found or token has expired"))
|
||||
return
|
||||
}
|
||||
state = reminderState{
|
||||
AckStatus: platformReminder.AckStatus,
|
||||
ScheduleID: platformReminder.ScheduleID,
|
||||
RemindStatus: platformReminder.RemindStatus,
|
||||
}
|
||||
table = "platform"
|
||||
}
|
||||
|
||||
if reminder.AckStatus == 1 {
|
||||
// 已经确认过了,直接显示已确认成功的 HTML
|
||||
if state.AckStatus == 1 {
|
||||
writeReminderAckAlreadyConfirmed(c)
|
||||
return
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
var err error
|
||||
if table == "backend" {
|
||||
_, err = models.Orm.QueryTable(new(models.BackendScheduleReminder)).
|
||||
Filter("ack_token", token).
|
||||
Filter("is_deleted", 0).
|
||||
Update(map[string]interface{}{
|
||||
"AckStatus": int8(1),
|
||||
"AckTime": now,
|
||||
"RemindStatus": int8(2),
|
||||
"UpdateTime": now,
|
||||
})
|
||||
} else {
|
||||
_, err = models.Orm.QueryTable(new(models.PlatformScheduleReminder)).
|
||||
Filter("ack_token", token).
|
||||
Filter("is_deleted", 0).
|
||||
Update(map[string]interface{}{
|
||||
"AckStatus": int8(1),
|
||||
"AckTime": now,
|
||||
"RemindStatus": int8(2),
|
||||
"UpdateTime": now,
|
||||
})
|
||||
}
|
||||
if err != nil {
|
||||
c.Ctx.Output.SetStatus(500)
|
||||
_ = c.Ctx.Output.Body([]byte("Database error, please try again later"))
|
||||
return
|
||||
}
|
||||
|
||||
// 只关闭命中来源表中、同一日程的其他待提醒记录,避免两套表互相影响。
|
||||
if table == "backend" {
|
||||
_, _ = models.Orm.QueryTable(new(models.BackendScheduleReminder)).
|
||||
Filter("schedule_id", state.ScheduleID).
|
||||
Filter("remind_status__in", 0, 1).
|
||||
Update(map[string]interface{}{
|
||||
"RemindStatus": int8(2),
|
||||
"UpdateTime": now,
|
||||
})
|
||||
} else {
|
||||
_, _ = models.Orm.QueryTable(new(models.PlatformScheduleReminder)).
|
||||
Filter("schedule_id", state.ScheduleID).
|
||||
Filter("remind_status__in", 0, 1).
|
||||
Update(map[string]interface{}{
|
||||
"RemindStatus": int8(2),
|
||||
"UpdateTime": now,
|
||||
})
|
||||
}
|
||||
|
||||
writeReminderAckSuccess(c)
|
||||
}
|
||||
|
||||
func writeReminderAckAlreadyConfirmed(c *ApiReminderController) {
|
||||
c.Ctx.Output.Header("Content-Type", "text/html; charset=utf-8")
|
||||
_ = c.Ctx.Output.Body([]byte(`
|
||||
<!DOCTYPE html>
|
||||
@@ -57,33 +140,9 @@ func (c *ApiReminderController) AckReminder() {
|
||||
</body>
|
||||
</html>
|
||||
`))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 更新确认状态为已确认,置 remind_status 为已结束(2)
|
||||
now := time.Now()
|
||||
reminder.AckStatus = 1
|
||||
reminder.AckTime = &now
|
||||
reminder.RemindStatus = 2
|
||||
reminder.UpdateTime = now
|
||||
|
||||
_, err = models.Orm.Update(&reminder, "AckStatus", "AckTime", "RemindStatus", "UpdateTime")
|
||||
if err != nil {
|
||||
c.Ctx.Output.SetStatus(500)
|
||||
_ = c.Ctx.Output.Body([]byte("Database error, please try again later"))
|
||||
return
|
||||
}
|
||||
|
||||
// 统一关闭该日程下的所有其他待提醒/提醒中渠道,防止重复打扰
|
||||
_, _ = models.Orm.QueryTable(new(models.PlatformScheduleReminder)).
|
||||
Filter("ScheduleID", reminder.ScheduleID).
|
||||
Filter("RemindStatus__in", 0, 1).
|
||||
Update(map[string]interface{}{
|
||||
"RemindStatus": int8(2),
|
||||
"UpdateTime": now,
|
||||
})
|
||||
|
||||
// 成功确认
|
||||
func writeReminderAckSuccess(c *ApiReminderController) {
|
||||
c.Ctx.Output.Header("Content-Type", "text/html; charset=utf-8")
|
||||
_ = c.Ctx.Output.Body([]byte(`
|
||||
<!DOCTYPE html>
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"server/models"
|
||||
"server/pkg/jwtutil"
|
||||
|
||||
"github.com/beego/beego/v2/client/orm"
|
||||
beego "github.com/beego/beego/v2/server/web"
|
||||
)
|
||||
|
||||
@@ -23,18 +24,18 @@ type AppReminderController struct {
|
||||
func (c *AppReminderController) appClaims() (*jwtutil.Claims, error) {
|
||||
auth := c.Ctx.Request.Header.Get("Authorization")
|
||||
if auth == "" {
|
||||
return nil, fmt.Errorf("未登录")
|
||||
return nil, orm.ErrNoRows
|
||||
}
|
||||
parts := strings.SplitN(auth, " ", 2)
|
||||
if len(parts) != 2 || parts[0] != "Bearer" {
|
||||
return nil, fmt.Errorf("认证信息格式错误")
|
||||
return nil, orm.ErrNoRows
|
||||
}
|
||||
claims, err := jwtutil.ParseToken(parts[1])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("无效的token")
|
||||
return nil, err
|
||||
}
|
||||
if claims.UserType != "backend" && claims.UserType != "app" && claims.UserType != "platform" {
|
||||
return nil, fmt.Errorf("无权访问")
|
||||
return nil, orm.ErrNoRows
|
||||
}
|
||||
return claims, nil
|
||||
}
|
||||
@@ -71,7 +72,7 @@ type appSchedulePayload struct {
|
||||
func (c *AppReminderController) GetList() {
|
||||
claims, err := c.appClaims()
|
||||
if err != nil {
|
||||
c.jsonErr(401, 401, err.Error())
|
||||
c.jsonErr(401, 401, "未登录或无权限")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -87,8 +88,9 @@ func (c *AppReminderController) GetList() {
|
||||
pageSize = 20
|
||||
}
|
||||
|
||||
qs := models.Orm.QueryTable(new(models.PlatformSchedule)).
|
||||
Filter("user_id", claims.UserID)
|
||||
qs := models.Orm.QueryTable(new(models.BackendSchedule)).
|
||||
Filter("user_id", claims.UserID).
|
||||
Filter("tid", claims.TenantId)
|
||||
|
||||
if keyword != "" {
|
||||
qs = qs.Filter("content__contains", keyword)
|
||||
@@ -96,17 +98,20 @@ func (c *AppReminderController) GetList() {
|
||||
|
||||
total, _ := qs.Count()
|
||||
|
||||
var schedules []models.PlatformSchedule
|
||||
var schedules []models.BackendSchedule
|
||||
_, err = qs.OrderBy("-id").Limit(pageSize, (page-1)*pageSize).All(&schedules)
|
||||
if err != nil {
|
||||
if err != nil && err != orm.ErrNoRows {
|
||||
c.jsonErr(500, 500, "查询失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
if schedules == nil {
|
||||
schedules = []models.BackendSchedule{}
|
||||
}
|
||||
|
||||
list := make([]map[string]interface{}, 0, len(schedules))
|
||||
for _, s := range schedules {
|
||||
var reminders []models.PlatformScheduleReminder
|
||||
_, _ = models.Orm.QueryTable(new(models.PlatformScheduleReminder)).
|
||||
var reminders []models.BackendScheduleReminder
|
||||
_, _ = models.Orm.QueryTable(new(models.BackendScheduleReminder)).
|
||||
Filter("schedule_id", s.ID).
|
||||
Filter("is_deleted", 0).
|
||||
All(&reminders)
|
||||
@@ -166,7 +171,7 @@ func (c *AppReminderController) GetList() {
|
||||
func (c *AppReminderController) GetDetail() {
|
||||
claims, err := c.appClaims()
|
||||
if err != nil {
|
||||
c.jsonErr(401, 401, err.Error())
|
||||
c.jsonErr(401, 401, "未登录或无权限")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -177,24 +182,25 @@ func (c *AppReminderController) GetDetail() {
|
||||
return
|
||||
}
|
||||
|
||||
var schedule models.PlatformSchedule
|
||||
err = models.Orm.QueryTable(new(models.PlatformSchedule)).
|
||||
var schedule models.BackendSchedule
|
||||
err = models.Orm.QueryTable(new(models.BackendSchedule)).
|
||||
Filter("id", id).
|
||||
Filter("user_id", claims.UserID).
|
||||
Filter("tid", claims.TenantId).
|
||||
One(&schedule)
|
||||
if err != nil {
|
||||
c.jsonErr(404, 404, "日程未找到")
|
||||
return
|
||||
}
|
||||
|
||||
var reminders []models.PlatformScheduleReminder
|
||||
_, _ = models.Orm.QueryTable(new(models.PlatformScheduleReminder)).
|
||||
var reminders []models.BackendScheduleReminder
|
||||
_, _ = models.Orm.QueryTable(new(models.BackendScheduleReminder)).
|
||||
Filter("schedule_id", schedule.ID).
|
||||
Filter("is_deleted", 0).
|
||||
All(&reminders)
|
||||
|
||||
channels := make([]string, 0, len(reminders))
|
||||
var first models.PlatformScheduleReminder
|
||||
var first models.BackendScheduleReminder
|
||||
for _, r := range reminders {
|
||||
channels = append(channels, r.RemindChannel)
|
||||
first = r
|
||||
@@ -236,7 +242,7 @@ func (c *AppReminderController) GetDetail() {
|
||||
func (c *AppReminderController) Create() {
|
||||
claims, err := c.appClaims()
|
||||
if err != nil {
|
||||
c.jsonErr(401, 401, err.Error())
|
||||
c.jsonErr(401, 401, "未登录或无权限")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -275,7 +281,8 @@ func (c *AppReminderController) Create() {
|
||||
title = "日程提醒"
|
||||
}
|
||||
|
||||
schedule := models.PlatformSchedule{
|
||||
schedule := models.BackendSchedule{
|
||||
Tid: claims.TenantId,
|
||||
Title: title,
|
||||
Content: content,
|
||||
ScheduleTime: schedTime,
|
||||
@@ -298,7 +305,8 @@ func (c *AppReminderController) Create() {
|
||||
|
||||
firstSendTime := schedTime.Add(-time.Duration(p.AdvanceMinutes) * time.Minute)
|
||||
|
||||
reminder := models.PlatformScheduleReminder{
|
||||
reminder := models.BackendScheduleReminder{
|
||||
Tid: claims.TenantId,
|
||||
ScheduleID: uint64(schedID),
|
||||
RemindChannel: ch,
|
||||
AdvanceMinutes: p.AdvanceMinutes,
|
||||
@@ -336,7 +344,7 @@ func (c *AppReminderController) Create() {
|
||||
func (c *AppReminderController) Update() {
|
||||
claims, err := c.appClaims()
|
||||
if err != nil {
|
||||
c.jsonErr(401, 401, err.Error())
|
||||
c.jsonErr(401, 401, "未登录或无权限")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -364,18 +372,19 @@ func (c *AppReminderController) Update() {
|
||||
return
|
||||
}
|
||||
|
||||
var schedule models.PlatformSchedule
|
||||
err = models.Orm.QueryTable(new(models.PlatformSchedule)).
|
||||
var schedule models.BackendSchedule
|
||||
err = models.Orm.QueryTable(new(models.BackendSchedule)).
|
||||
Filter("id", id).
|
||||
Filter("user_id", claims.UserID).
|
||||
Filter("tid", claims.TenantId).
|
||||
One(&schedule)
|
||||
if err != nil {
|
||||
c.jsonErr(404, 404, "日程未找到")
|
||||
return
|
||||
}
|
||||
|
||||
var reminders []models.PlatformScheduleReminder
|
||||
_, _ = models.Orm.QueryTable(new(models.PlatformScheduleReminder)).
|
||||
var reminders []models.BackendScheduleReminder
|
||||
_, _ = models.Orm.QueryTable(new(models.BackendScheduleReminder)).
|
||||
Filter("schedule_id", id).
|
||||
Filter("is_deleted", 0).
|
||||
All(&reminders)
|
||||
@@ -414,7 +423,7 @@ func (c *AppReminderController) Update() {
|
||||
}
|
||||
|
||||
// 软删除旧提醒,重建
|
||||
_, _ = models.Orm.QueryTable(new(models.PlatformScheduleReminder)).
|
||||
_, _ = models.Orm.QueryTable(new(models.BackendScheduleReminder)).
|
||||
Filter("schedule_id", id).
|
||||
Update(map[string]interface{}{
|
||||
"IsDeleted": 1,
|
||||
@@ -432,7 +441,8 @@ func (c *AppReminderController) Update() {
|
||||
|
||||
firstSendTime := schedTime.Add(-time.Duration(p.AdvanceMinutes) * time.Minute)
|
||||
|
||||
reminder := models.PlatformScheduleReminder{
|
||||
reminder := models.BackendScheduleReminder{
|
||||
Tid: claims.TenantId,
|
||||
ScheduleID: id,
|
||||
RemindChannel: ch,
|
||||
AdvanceMinutes: p.AdvanceMinutes,
|
||||
@@ -470,7 +480,7 @@ func (c *AppReminderController) Update() {
|
||||
func (c *AppReminderController) Delete() {
|
||||
claims, err := c.appClaims()
|
||||
if err != nil {
|
||||
c.jsonErr(401, 401, err.Error())
|
||||
c.jsonErr(401, 401, "未登录或无权限")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -481,18 +491,19 @@ func (c *AppReminderController) Delete() {
|
||||
return
|
||||
}
|
||||
|
||||
var schedule models.PlatformSchedule
|
||||
err = models.Orm.QueryTable(new(models.PlatformSchedule)).
|
||||
var schedule models.BackendSchedule
|
||||
err = models.Orm.QueryTable(new(models.BackendSchedule)).
|
||||
Filter("id", id).
|
||||
Filter("user_id", claims.UserID).
|
||||
Filter("tid", claims.TenantId).
|
||||
One(&schedule)
|
||||
if err != nil {
|
||||
c.jsonErr(404, 404, "日程未找到")
|
||||
return
|
||||
}
|
||||
|
||||
var reminders []models.PlatformScheduleReminder
|
||||
_, _ = models.Orm.QueryTable(new(models.PlatformScheduleReminder)).
|
||||
var reminders []models.BackendScheduleReminder
|
||||
_, _ = models.Orm.QueryTable(new(models.BackendScheduleReminder)).
|
||||
Filter("schedule_id", id).
|
||||
Filter("is_deleted", 0).
|
||||
All(&reminders)
|
||||
@@ -512,9 +523,9 @@ func (c *AppReminderController) Delete() {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = models.Orm.QueryTable(new(models.PlatformSchedule)).Filter("id", id).Delete()
|
||||
_, err = models.Orm.QueryTable(new(models.BackendSchedule)).Filter("id", id).Delete()
|
||||
if err == nil {
|
||||
_, _ = models.Orm.QueryTable(new(models.PlatformScheduleReminder)).
|
||||
_, _ = models.Orm.QueryTable(new(models.BackendScheduleReminder)).
|
||||
Filter("schedule_id", id).
|
||||
Update(map[string]interface{}{
|
||||
"IsDeleted": 1,
|
||||
@@ -530,7 +541,7 @@ func (c *AppReminderController) Delete() {
|
||||
func (c *AppReminderController) ToggleComplete() {
|
||||
claims, err := c.appClaims()
|
||||
if err != nil {
|
||||
c.jsonErr(401, 401, err.Error())
|
||||
c.jsonErr(401, 401, "未登录或无权限")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -541,18 +552,19 @@ func (c *AppReminderController) ToggleComplete() {
|
||||
return
|
||||
}
|
||||
|
||||
var schedule models.PlatformSchedule
|
||||
err = models.Orm.QueryTable(new(models.PlatformSchedule)).
|
||||
var schedule models.BackendSchedule
|
||||
err = models.Orm.QueryTable(new(models.BackendSchedule)).
|
||||
Filter("id", id).
|
||||
Filter("user_id", claims.UserID).
|
||||
Filter("tid", claims.TenantId).
|
||||
One(&schedule)
|
||||
if err != nil {
|
||||
c.jsonErr(404, 404, "日程未找到")
|
||||
return
|
||||
}
|
||||
|
||||
var reminders []models.PlatformScheduleReminder
|
||||
_, _ = models.Orm.QueryTable(new(models.PlatformScheduleReminder)).
|
||||
var reminders []models.BackendScheduleReminder
|
||||
_, _ = models.Orm.QueryTable(new(models.BackendScheduleReminder)).
|
||||
Filter("schedule_id", id).
|
||||
Filter("is_deleted", 0).
|
||||
All(&reminders)
|
||||
|
||||
@@ -703,13 +703,20 @@ func (c *BackendReminderController) TestReminder() {
|
||||
}
|
||||
|
||||
dummyToken := "test-token-for-verification"
|
||||
reminder := &models.PlatformScheduleReminder{
|
||||
reminder := &models.BackendScheduleReminder{
|
||||
Tid: claims.TenantId,
|
||||
RemindChannel: ch,
|
||||
ReceiverUserID: uint64(claims.UserID),
|
||||
AckToken: &dummyToken,
|
||||
}
|
||||
|
||||
success, sendErr := sender.Send(context.Background(), reminder, "[测试]"+p.Title, p.Content)
|
||||
success, sendErr := sender.Send(context.Background(), services.ReminderData{
|
||||
RemindChannel: reminder.RemindChannel,
|
||||
ReceiverUserID: reminder.ReceiverUserID,
|
||||
ReceiverTarget: reminder.ReceiverTarget,
|
||||
AckToken: reminder.AckToken,
|
||||
Tid: reminder.Tid,
|
||||
}, "[测试]"+p.Title, p.Content)
|
||||
msg := "发送成功"
|
||||
if !success {
|
||||
msg = "发送失败"
|
||||
|
||||
@@ -616,7 +616,12 @@ func (c *PlatformReminderController) TestReminder() {
|
||||
AckToken: &dummyToken,
|
||||
}
|
||||
|
||||
success, sendErr := sender.Send(context.Background(), reminder, "[测试]"+p.Title, p.Content)
|
||||
success, sendErr := sender.Send(context.Background(), services.ReminderData{
|
||||
RemindChannel: reminder.RemindChannel,
|
||||
ReceiverUserID: reminder.ReceiverUserID,
|
||||
ReceiverTarget: reminder.ReceiverTarget,
|
||||
AckToken: reminder.AckToken,
|
||||
}, "[测试]"+p.Title, p.Content)
|
||||
msg := "发送成功"
|
||||
if !success {
|
||||
msg = "发送失败"
|
||||
|
||||
@@ -15,15 +15,23 @@ import (
|
||||
"server/models"
|
||||
)
|
||||
|
||||
type ReminderData struct {
|
||||
RemindChannel string
|
||||
ReceiverUserID uint64
|
||||
ReceiverTarget *string
|
||||
AckToken *string
|
||||
Tid int
|
||||
}
|
||||
|
||||
// ReminderSender 提醒发送接口
|
||||
type ReminderSender interface {
|
||||
Send(ctx context.Context, reminder *models.PlatformScheduleReminder, title, content string) (success bool, err error)
|
||||
Send(ctx context.Context, reminder ReminderData, title, content string) (success bool, err error)
|
||||
}
|
||||
|
||||
// SMSSender 短信发送实现
|
||||
type SMSSender struct{}
|
||||
|
||||
func (s *SMSSender) Send(ctx context.Context, reminder *models.PlatformScheduleReminder, title, content string) (bool, error) {
|
||||
func (s *SMSSender) Send(ctx context.Context, reminder ReminderData, title, content string) (bool, error) {
|
||||
backendURL, apiKey, err := getDefaultSystemSMSConfig()
|
||||
if err != nil {
|
||||
return false, err
|
||||
@@ -73,7 +81,7 @@ func (s *SMSSender) Send(ctx context.Context, reminder *models.PlatformScheduleR
|
||||
// EmailSender 邮件发送实现
|
||||
type EmailSender struct{}
|
||||
|
||||
func (s *EmailSender) Send(ctx context.Context, reminder *models.PlatformScheduleReminder, title, content string) (bool, error) {
|
||||
func (s *EmailSender) Send(ctx context.Context, reminder ReminderData, title, content string) (bool, error) {
|
||||
emails, err := ListSystemEmails()
|
||||
if err != nil || len(emails) == 0 {
|
||||
return false, fmt.Errorf("未配置系统邮箱")
|
||||
@@ -147,7 +155,7 @@ func (s *EmailSender) Send(ctx context.Context, reminder *models.PlatformSchedul
|
||||
// BarkSender Bark 推送实现
|
||||
type BarkSender struct{}
|
||||
|
||||
func (s *BarkSender) Send(ctx context.Context, reminder *models.PlatformScheduleReminder, title, content string) (bool, error) {
|
||||
func (s *BarkSender) Send(ctx context.Context, reminder ReminderData, title, content string) (bool, error) {
|
||||
deviceKey := ""
|
||||
if reminder.ReceiverTarget != nil && *reminder.ReceiverTarget != "" {
|
||||
deviceKey = *reminder.ReceiverTarget
|
||||
@@ -204,7 +212,7 @@ func (s *BarkSender) Send(ctx context.Context, reminder *models.PlatformSchedule
|
||||
// SiteMsgSender 站内信发送实现
|
||||
type SiteMsgSender struct{}
|
||||
|
||||
func (s *SiteMsgSender) Send(ctx context.Context, reminder *models.PlatformScheduleReminder, title, content string) (bool, error) {
|
||||
func (s *SiteMsgSender) Send(ctx context.Context, reminder ReminderData, title, content string) (bool, error) {
|
||||
now := time.Now()
|
||||
msg := &models.SystemReminderList{
|
||||
Title: title,
|
||||
@@ -212,9 +220,11 @@ func (s *SiteMsgSender) Send(ctx context.Context, reminder *models.PlatformSched
|
||||
SenderID: 0,
|
||||
SenderType: "system",
|
||||
ReceiverID: reminder.ReceiverUserID,
|
||||
ReceiverType: "platform", // 平台端用户
|
||||
ReceiverType: "tenant", // backend/租户用户
|
||||
IsRead: 0,
|
||||
CreateTime: &now,
|
||||
TargetType: "tenant",
|
||||
TargetTenantID: uint64(reminder.Tid),
|
||||
}
|
||||
_, err := models.Orm.Insert(msg)
|
||||
if err != nil {
|
||||
@@ -255,7 +265,7 @@ func scanAndSendReminders() {
|
||||
|
||||
// 2. 抢占待处理的数据(乐观锁防并发重复发送)
|
||||
_, err := models.Orm.Raw(`
|
||||
UPDATE yz_platform_schedule_reminder
|
||||
UPDATE yz_backend_schedule_reminder
|
||||
SET scan_lock = ?, update_time = NOW()
|
||||
WHERE next_remind_time <= ?
|
||||
AND remind_status IN (0, 1)
|
||||
@@ -267,8 +277,8 @@ func scanAndSendReminders() {
|
||||
}
|
||||
|
||||
// 3. 查询自己锁定成功的数据
|
||||
var list []models.PlatformScheduleReminder
|
||||
_, err = models.Orm.QueryTable(new(models.PlatformScheduleReminder)).
|
||||
var list []models.BackendScheduleReminder
|
||||
_, err = models.Orm.QueryTable(new(models.BackendScheduleReminder)).
|
||||
Filter("scan_lock", scanBatch).
|
||||
Filter("remind_status__in", 0, 1).
|
||||
Filter("is_deleted", 0).
|
||||
@@ -289,8 +299,8 @@ func scanAndSendReminders() {
|
||||
reminder := &list[i]
|
||||
|
||||
// 3.1 获取日程信息(主要拿 Content,Title 统一为 "日程提醒")
|
||||
var schedule models.PlatformSchedule
|
||||
err := models.Orm.QueryTable(new(models.PlatformSchedule)).
|
||||
var schedule models.BackendSchedule
|
||||
err := models.Orm.QueryTable(new(models.BackendSchedule)).
|
||||
Filter("id", reminder.ScheduleID).
|
||||
One(&schedule)
|
||||
title := "日程提醒"
|
||||
@@ -302,7 +312,7 @@ func scanAndSendReminders() {
|
||||
sender, ok := senders[reminder.RemindChannel]
|
||||
if !ok {
|
||||
// 未知渠道,直接强制置为结束
|
||||
_, _ = models.Orm.QueryTable(new(models.PlatformScheduleReminder)).
|
||||
_, _ = models.Orm.QueryTable(new(models.BackendScheduleReminder)).
|
||||
Filter("id", reminder.ID).
|
||||
Update(map[string]interface{}{
|
||||
"remind_status": 2,
|
||||
@@ -314,7 +324,13 @@ func scanAndSendReminders() {
|
||||
|
||||
// 执行发送
|
||||
ctx := context.Background()
|
||||
success, sendErr := sender.Send(ctx, reminder, title, content)
|
||||
success, sendErr := sender.Send(ctx, ReminderData{
|
||||
RemindChannel: reminder.RemindChannel,
|
||||
ReceiverUserID: reminder.ReceiverUserID,
|
||||
ReceiverTarget: reminder.ReceiverTarget,
|
||||
AckToken: reminder.AckToken,
|
||||
Tid: reminder.Tid,
|
||||
}, title, content)
|
||||
|
||||
// 3.2 记录发送流水日志
|
||||
sendResult := int8(0)
|
||||
@@ -329,7 +345,8 @@ func scanAndSendReminders() {
|
||||
failReason = &errStr
|
||||
}
|
||||
|
||||
logRow := &models.PlatformScheduleReminderSendLog{
|
||||
logRow := &models.BackendScheduleReminderSendLog{
|
||||
Tid: reminder.Tid,
|
||||
ReminderID: reminder.ID,
|
||||
SendTime: time.Now(),
|
||||
SendResult: sendResult,
|
||||
@@ -358,7 +375,7 @@ func scanAndSendReminders() {
|
||||
}
|
||||
|
||||
// 3.4 回写主表记录
|
||||
_, _ = models.Orm.QueryTable(new(models.PlatformScheduleReminder)).
|
||||
_, _ = models.Orm.QueryTable(new(models.BackendScheduleReminder)).
|
||||
Filter("id", reminder.ID).
|
||||
Update(map[string]interface{}{
|
||||
"SendCount": newSendCount,
|
||||
|
||||
Generated
+170
-300
@@ -9,24 +9,14 @@
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "^2.3.2",
|
||||
"@tiptap/extension-color": "^3.27.4",
|
||||
"@tiptap/extension-highlight": "^3.27.4",
|
||||
"@tiptap/extension-image": "^3.27.4",
|
||||
"@tiptap/extension-link": "^3.27.4",
|
||||
"@tiptap/extension-placeholder": "^3.27.4",
|
||||
"@tiptap/extension-subscript": "^3.27.4",
|
||||
"@tiptap/extension-superscript": "^3.27.4",
|
||||
"@tiptap/extension-table": "^3.27.4",
|
||||
"@tiptap/extension-table-cell": "^3.27.4",
|
||||
"@tiptap/extension-table-header": "^3.27.4",
|
||||
"@tiptap/extension-table-row": "^3.27.4",
|
||||
"@tiptap/extension-text-align": "^3.27.4",
|
||||
"@tiptap/extension-text-style": "^3.27.4",
|
||||
"@tiptap/extension-typography": "^3.27.4",
|
||||
"@tiptap/extension-underline": "^3.27.4",
|
||||
"@tiptap/pm": "^3.27.4",
|
||||
"@tiptap/starter-kit": "^3.27.4",
|
||||
"@tiptap/vue-3": "^3.27.4",
|
||||
"@tiptap/extension-color": "^3.28.0",
|
||||
"@tiptap/extension-image": "^3.28.0",
|
||||
"@tiptap/extension-link": "^3.28.0",
|
||||
"@tiptap/extension-text-align": "^3.28.0",
|
||||
"@tiptap/extension-text-style": "^3.28.0",
|
||||
"@tiptap/extension-underline": "^3.28.0",
|
||||
"@tiptap/starter-kit": "^3.28.0",
|
||||
"@tiptap/vue-3": "^3.28.0",
|
||||
"@umoteam/editor": "^10.2.1",
|
||||
"axios": "^1.13.1",
|
||||
"chart": "^0.1.2",
|
||||
@@ -1174,49 +1164,49 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@tiptap/core": {
|
||||
"version": "3.27.4",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/core/-/core-3.27.4.tgz",
|
||||
"integrity": "sha512-8W/GwlEn0JwNdpyVfTWcXwHYUpj9BWwO++YxtizmgjJzlwigSh7/xLVJMwVykuQHQ2fCq5rkUvmBRtpHOMLUQA==",
|
||||
"version": "3.28.0",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/core/-/core-3.28.0.tgz",
|
||||
"integrity": "sha512-gUuD5WAYfbDxNSSJya/emh2KSzXZXLUYKW4fEnc1AQ5FE2twzh4LJ9UlKFIawigrUCAksWI5Fy1hRbv+5m4ZdQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/pm": "3.27.4"
|
||||
"@tiptap/pm": "3.28.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-blockquote": {
|
||||
"version": "3.27.4",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-blockquote/-/extension-blockquote-3.27.4.tgz",
|
||||
"integrity": "sha512-d1tOHgP3R5cOE+Ot8qL/dkLXRByajgn+j6cCXHqDtmJO2wsK9knmbKQ0SEjbKrU6OgHrTnY/EotNxBEBW9HGoA==",
|
||||
"version": "3.28.0",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-blockquote/-/extension-blockquote-3.28.0.tgz",
|
||||
"integrity": "sha512-y8Xi6Z3AQLXedz0J8Z3kDsu7SKBmL50gKVXx3RK1Oo1cuCGhNChm3syChkAz3PLAbrPUM5rvJDSZdF2jUrDnng==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.27.4",
|
||||
"@tiptap/pm": "3.27.4"
|
||||
"@tiptap/core": "3.28.0",
|
||||
"@tiptap/pm": "3.28.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-bold": {
|
||||
"version": "3.27.4",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-bold/-/extension-bold-3.27.4.tgz",
|
||||
"integrity": "sha512-wTtJUUAxCAZ01ICH2DNlOBzzHKRQ1ZST8aRYtIhBPzqEUhnJaKGcjnDB4X49fqPi48iXaPxzhsInDl+rVUujWg==",
|
||||
"version": "3.28.0",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-bold/-/extension-bold-3.28.0.tgz",
|
||||
"integrity": "sha512-JhZQmr0AU741bOwjVMfuwJdK4g0TQwwPbeca9aqKHv5zvZw4i4G9G6fESVyMFc3Yag1ffpnq5EtNldHKTnMhlw==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.27.4"
|
||||
"@tiptap/core": "3.28.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-bubble-menu": {
|
||||
"version": "3.27.4",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-bubble-menu/-/extension-bubble-menu-3.27.4.tgz",
|
||||
"integrity": "sha512-Poy7xwcD3POG5ew/TW7mYXv7m++vCchvHxPUqIfnTxBxvvvqDZkPYFWZS1lvPrSBtm1DcfUTQAgVutM5NDZ99Q==",
|
||||
"version": "3.28.0",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-bubble-menu/-/extension-bubble-menu-3.28.0.tgz",
|
||||
"integrity": "sha512-7AUNoHj2K4XLKCgW4uspeD/ENejPu2BeHvLTsiOoIO+XXDNSi2j0bbaIS8f2s/qnFirscwp/sbznp1qph/76qg==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
@@ -1227,48 +1217,48 @@
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.27.4",
|
||||
"@tiptap/pm": "3.27.4"
|
||||
"@tiptap/core": "3.28.0",
|
||||
"@tiptap/pm": "3.28.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-bullet-list": {
|
||||
"version": "3.27.4",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-bullet-list/-/extension-bullet-list-3.27.4.tgz",
|
||||
"integrity": "sha512-rvja0N1RnwGJAVwDdbUfDIJ4NoT+KjPFaZudKiPuEMfMHfbqe4xcbbC2hsfs61JNcl2xmx+ohV6lzD9YxxJl1w==",
|
||||
"version": "3.28.0",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-bullet-list/-/extension-bullet-list-3.28.0.tgz",
|
||||
"integrity": "sha512-dSVuNiH7PFMmWGkNER9vfUb5bXUHDARvHbJ3l+APEb+ZiusVN1KFdM3nd/RsW/Rt5Gd3XwlIEU/c2Uf7cxYDcw==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/extension-list": "3.27.4"
|
||||
"@tiptap/extension-list": "3.28.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-code": {
|
||||
"version": "3.27.4",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-code/-/extension-code-3.27.4.tgz",
|
||||
"integrity": "sha512-aPc7opCR1ylK4m4c2lsjLsGpEBD1fLQQKWd5PbZiJvrTF8gkdGZlYLt9A6VukpxeJyHhb22Jaj4fxgKmGMeTtw==",
|
||||
"version": "3.28.0",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-code/-/extension-code-3.28.0.tgz",
|
||||
"integrity": "sha512-AUw2Acof3CQE6Q6Y22saK4lyg0nkeJ4XXniU65TdAi/9TE66TGiO4NQJJNNPgu8+VMEwl5j8VsIFK8sfTcNYtg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.27.4"
|
||||
"@tiptap/core": "3.28.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-code-block": {
|
||||
"version": "3.27.4",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-code-block/-/extension-code-block-3.27.4.tgz",
|
||||
"integrity": "sha512-a5caWfWN6Z6usy48vzJDDOhWoA6+rFFCHGpQM7jXn/7rRzYPcvBzTZUGptjEbltj4YqtrQ2tVwTJcCtbb+mknA==",
|
||||
"version": "3.28.0",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-code-block/-/extension-code-block-3.28.0.tgz",
|
||||
"integrity": "sha512-bHITDzT0umTLh+SiEVQzIXkCMt/TzbPM1+HQy9ZxgQDHAJj/vdmfNAnP3RCOrz4lETXyhNQ2b6kxeu3lWckxyA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.27.4",
|
||||
"@tiptap/pm": "3.27.4"
|
||||
"@tiptap/core": "3.28.0",
|
||||
"@tiptap/pm": "3.28.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-code-block-lowlight": {
|
||||
@@ -1305,16 +1295,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-color": {
|
||||
"version": "3.27.4",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-color/-/extension-color-3.27.4.tgz",
|
||||
"integrity": "sha512-uGbgErKGKO4OTBGqnXOA1CGXa3IqoBaiPBGcHu/px01fS8EVFu0A7q5HS6vxFiMK6qW5x71sEpCA+FUINMAb3g==",
|
||||
"version": "3.28.0",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-color/-/extension-color-3.28.0.tgz",
|
||||
"integrity": "sha512-YbUMUdrgU04GDYoii1wuFVkiTSQoaEQh04kwgQayEQ46aUBEnnaJitWdp39aGMWYTIXD/c9K9cr5Vg8GSKcVxA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/extension-text-style": "3.27.4"
|
||||
"@tiptap/extension-text-style": "3.28.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-details": {
|
||||
@@ -1333,16 +1323,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-document": {
|
||||
"version": "3.27.4",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-document/-/extension-document-3.27.4.tgz",
|
||||
"integrity": "sha512-7nAqgfkgb9HADBeCTnOHuTiyZuxfxvMPT3nH4OZeY+cmtkI1On3QffqlmtcUPvNbkhT3o9ehA1hVfCnQ1Ye4LQ==",
|
||||
"version": "3.28.0",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-document/-/extension-document-3.28.0.tgz",
|
||||
"integrity": "sha512-5SAKtlB1Tr/eZFhISL86HqmUup6rItvPtuPyRjmZo/VgbMwXEwiyAh1sMgFp5VNaeSMM14vJSyQpjhSaOmaBqg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.27.4"
|
||||
"@tiptap/core": "3.28.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-drag-handle": {
|
||||
@@ -1382,22 +1372,22 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-dropcursor": {
|
||||
"version": "3.27.4",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-dropcursor/-/extension-dropcursor-3.27.4.tgz",
|
||||
"integrity": "sha512-RiZasQJuUTUO3aME16Bn8eJH7cYnvhT5JCFDFq0ya/1iFI9wUQA2NJC5tb5TrZ74+sQwkYU9VzexnchM481Y9w==",
|
||||
"version": "3.28.0",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-dropcursor/-/extension-dropcursor-3.28.0.tgz",
|
||||
"integrity": "sha512-JA+dXQjjfJBpD0nVsZeddGVXRsmanESM9+8CtM35hI9wJnYMXay/B+5GUhswO20zhT3zhB2ZOTGe9knu6A8nIQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/extensions": "3.27.4"
|
||||
"@tiptap/extensions": "3.28.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-floating-menu": {
|
||||
"version": "3.27.4",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-floating-menu/-/extension-floating-menu-3.27.4.tgz",
|
||||
"integrity": "sha512-tnZywwoNDuEcUZmYYIztXl3PpIKUq+gKeaYPuZhpYEVTThU44tzK3ZuFOmd+qf2aAa1MQwxKWqUuLpNK77bwNw==",
|
||||
"version": "3.28.0",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-floating-menu/-/extension-floating-menu-3.28.0.tgz",
|
||||
"integrity": "sha512-59SECvJq3pQfeJBuydEdhQqrpl0oDlk8N1Ovs1Si3/fJa6rEQAJB2zIvcpBHky9Z+5JodI2eueDnv8eimiyGbg==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"funding": {
|
||||
@@ -1406,87 +1396,74 @@
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@floating-ui/dom": "^1.0.0",
|
||||
"@tiptap/core": "3.27.4",
|
||||
"@tiptap/pm": "3.27.4"
|
||||
"@tiptap/core": "3.28.0",
|
||||
"@tiptap/pm": "3.28.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-gapcursor": {
|
||||
"version": "3.27.4",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-gapcursor/-/extension-gapcursor-3.27.4.tgz",
|
||||
"integrity": "sha512-svLwSKcFhzpcJeXvxxKkRFuQpykmXrQefVhEsaXq0L95yJIIAGKMRmQC3mxKdzL2j0P9cY7V41bNVSyOAyvclw==",
|
||||
"version": "3.28.0",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-gapcursor/-/extension-gapcursor-3.28.0.tgz",
|
||||
"integrity": "sha512-Wo73kM4q8z4Va9i4+0n1cO0UEMVUVBHPqM6cAqEYXjB4T48LQkKjRsiQydCezm185rQAsmm1dyi72gtvVQfdMg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/extensions": "3.27.4"
|
||||
"@tiptap/extensions": "3.28.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-hard-break": {
|
||||
"version": "3.27.4",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-hard-break/-/extension-hard-break-3.27.4.tgz",
|
||||
"integrity": "sha512-W+Z9pmDgqjbdu3NeZOQrzA15iM4w60Yd8l2CYzxcdApPVIfYzb2S3a7+u1RqW9wnTYb6xyZjASmFNfxXS4P4cg==",
|
||||
"version": "3.28.0",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-hard-break/-/extension-hard-break-3.28.0.tgz",
|
||||
"integrity": "sha512-JHIFjX1luJgQ4VFEkIeXZpbc54Qiw+69P8FmlazYTh7AIJ6iLCpMFgQFELnivEAZ+/vS0lMPQubg0rCeM3UrHw==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.27.4"
|
||||
"@tiptap/core": "3.28.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-heading": {
|
||||
"version": "3.27.4",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-heading/-/extension-heading-3.27.4.tgz",
|
||||
"integrity": "sha512-RgvpxzuYk6QEK+az+eiXpWvGlUso42zNcGnjyUrvskoZjS47MbhSg8ylRYQSRtXE0ETlXhAx4J7iGlGr72kyIw==",
|
||||
"version": "3.28.0",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-heading/-/extension-heading-3.28.0.tgz",
|
||||
"integrity": "sha512-rKjGG/Ik2lNaXBNVmONEDm5DBfGDLM1NWgSf5RRfBISrH8Lm1xqFruOB9tIaB0YUoSV3SBOiwTF9svmzvKSoRA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.27.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-highlight": {
|
||||
"version": "3.27.4",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-highlight/-/extension-highlight-3.27.4.tgz",
|
||||
"integrity": "sha512-STRX1qJLhTZslBF8fEE5qpTGrFd/g7Ufidjxt84p0uT8FrtcbfPUwyweeYwhZp7Iw8n+qODGYnheJTOpfaW2JA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.27.4"
|
||||
"@tiptap/core": "3.28.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-horizontal-rule": {
|
||||
"version": "3.27.4",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-3.27.4.tgz",
|
||||
"integrity": "sha512-2eQU/55nE5mhMJHALtLMuBL3dcVJUDVVT7n+uZYMaYE63BtCvC4VS08YLFSR7JZSVJIlgVAmdt5nAw0B+rEPNA==",
|
||||
"version": "3.28.0",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-3.28.0.tgz",
|
||||
"integrity": "sha512-neBCMWprkppQUoLWyeJZDHqBw+xKX2oNhLD9MbFlhKIr092zgfP4mpCvQnSkn1OHl156KzZMp070+NyLBjgQ7A==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.27.4",
|
||||
"@tiptap/pm": "3.27.4"
|
||||
"@tiptap/core": "3.28.0",
|
||||
"@tiptap/pm": "3.28.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-image": {
|
||||
"version": "3.27.4",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-image/-/extension-image-3.27.4.tgz",
|
||||
"integrity": "sha512-yQ8CazyOL4z1/NbV1NLGv6DvchVhOXHH3uQ7md5VX/IGZruFpnm8IpF9MDpdAUxUFmTsXJDYyO2lWGO1PYWG8A==",
|
||||
"version": "3.28.0",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-image/-/extension-image-3.28.0.tgz",
|
||||
"integrity": "sha512-aKGCdEjyujUcQ6tEtq4EPbKxEC16QsKapv3DeZs1c/UHFiEUalbbPHBnxjGnupiLz75IR+07GYqBoZ81kSCxiA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.27.4"
|
||||
"@tiptap/core": "3.28.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-invisible-characters": {
|
||||
@@ -1505,22 +1482,22 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-italic": {
|
||||
"version": "3.27.4",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-italic/-/extension-italic-3.27.4.tgz",
|
||||
"integrity": "sha512-PeZT4XbyxAp7Lqo/hfA1k5LI27g1RlgS+YgXp2CeHXIrUfSpO5HlZXh02Bvb0pOdl3RFw2tEKtlHzjt8Y1+Nwg==",
|
||||
"version": "3.28.0",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-italic/-/extension-italic-3.28.0.tgz",
|
||||
"integrity": "sha512-Yur/ELz6dNVKQC7m8wGjtoLFxamGjJmA0rUEEOacTH6J39aFmcSxYkEGNDkYHbZFyHFYqbej6eI3VE0h08O0mg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.27.4"
|
||||
"@tiptap/core": "3.28.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-link": {
|
||||
"version": "3.27.4",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-link/-/extension-link-3.27.4.tgz",
|
||||
"integrity": "sha512-6K/FkNwMLWWQbNWKlycrUPTN7YcyVFdFwZncoBXe5WyarRjLTGw7ywafnCI9PDIWSq7ttzVL4NgjN2IN8kBXww==",
|
||||
"version": "3.28.0",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-link/-/extension-link-3.28.0.tgz",
|
||||
"integrity": "sha512-hy/PqSeTyl317yseFcHGE+3XVfQKQYaL4uZuj27xlrcO7MZ15drt1h9sUZy1FTBF3mr8676pQu7aoEm/Ww4ZRA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"linkifyjs": "^4.3.3"
|
||||
@@ -1530,48 +1507,48 @@
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.27.4",
|
||||
"@tiptap/pm": "3.27.4"
|
||||
"@tiptap/core": "3.28.0",
|
||||
"@tiptap/pm": "3.28.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-list": {
|
||||
"version": "3.27.4",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-list/-/extension-list-3.27.4.tgz",
|
||||
"integrity": "sha512-A0BgmRO1RE0yLCx9w7GQITtKfS9wLE5cdngSYDiSpwulcXJhJjKm5mZ4OUZmks2VN4HO5jMl2BWCGt2NSDhA+w==",
|
||||
"version": "3.28.0",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-list/-/extension-list-3.28.0.tgz",
|
||||
"integrity": "sha512-zQ66i5DuhVOndmZ0d7H475Y5Yb+BMx+zfCjFkCzEc6WVef5MumtxBVTkGLQ0ibxUaD71s4QQZbjHWagpaTg0eQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.27.4",
|
||||
"@tiptap/pm": "3.27.4"
|
||||
"@tiptap/core": "3.28.0",
|
||||
"@tiptap/pm": "3.28.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-list-item": {
|
||||
"version": "3.27.4",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-list-item/-/extension-list-item-3.27.4.tgz",
|
||||
"integrity": "sha512-z5TVuPw2mkK0B/x+gFg3uUV7tBdaElDFg0zVgnXZCqlSVTLfIyInOOnG5LTWoAd9BdzBjGrzE3PohDcLVDDGBQ==",
|
||||
"version": "3.28.0",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-list-item/-/extension-list-item-3.28.0.tgz",
|
||||
"integrity": "sha512-GbXrnMac6knSetZY33NHwOrgXFPqH28uCklQqmOZQlsrdGqezDKk31qoEMr4GsKW9n/lViAeuc07oIzwLwCMng==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/extension-list": "3.27.4"
|
||||
"@tiptap/extension-list": "3.28.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-list-keymap": {
|
||||
"version": "3.27.4",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-list-keymap/-/extension-list-keymap-3.27.4.tgz",
|
||||
"integrity": "sha512-on7JNDi7Eqz7UdZeZdiO83bQHo0flVDHzjmtR+v/nrCGW9H15D3CHs5+4ozLDiCvTK8tbkBuut/l9AWNxcCE/Q==",
|
||||
"version": "3.28.0",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-list-keymap/-/extension-list-keymap-3.28.0.tgz",
|
||||
"integrity": "sha512-u9Wks8c/eQAv0RkULNggOyTKDD69WVbcV9H5cbasPDUbq5XbEFVa9ajxhEGfMmQ5et3EX0QL8qBi50K0GqbIjA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/extension-list": "3.27.4"
|
||||
"@tiptap/extension-list": "3.28.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-mathematics": {
|
||||
@@ -1619,123 +1596,42 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-ordered-list": {
|
||||
"version": "3.27.4",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-ordered-list/-/extension-ordered-list-3.27.4.tgz",
|
||||
"integrity": "sha512-bHwLiof0FqJfWzB0act7oEKMTZatEKQ4IYCvmyF5EktjMs4kxEatkPp4Yx/1LSYSjLy1MMT7oLELyaz2FFYyXA==",
|
||||
"version": "3.28.0",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-ordered-list/-/extension-ordered-list-3.28.0.tgz",
|
||||
"integrity": "sha512-OZNYrKKL9D01ySOujlNbKlLS9/3wGgKNYeoHZUg0e+Ta8WPVvL3W1zH6TgiU5sF2ZSGUBoq3w7mdaO/iROlUkw==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/extension-list": "3.27.4"
|
||||
"@tiptap/extension-list": "3.28.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-paragraph": {
|
||||
"version": "3.27.4",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-paragraph/-/extension-paragraph-3.27.4.tgz",
|
||||
"integrity": "sha512-8Dnr1J5s/s4XYYuEF3b784NnCxLjXOlQpmGyXRxTAzW7JaOP08tIUJWVNvSMekfXc2vXa33HUbqjxyyWZEQ6LQ==",
|
||||
"version": "3.28.0",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-paragraph/-/extension-paragraph-3.28.0.tgz",
|
||||
"integrity": "sha512-8UMlQIjzqf6r2hSJ/VeJ00RqaOrOB1J5rTk02Vcw2pYeHkOqp+B0ff0HFu4abT9x1q4oXrBAgMsxRtgh/kR14Q==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.27.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-placeholder": {
|
||||
"version": "3.27.4",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-placeholder/-/extension-placeholder-3.27.4.tgz",
|
||||
"integrity": "sha512-7hBoFLeddCv1WzkqB0x3coZ1Hp9WZ9wLoRXIUtUhRKMpzFq2IlTtW1iw88g9pTJnL98bCCElN4DZ4mYtaQvmgA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/extensions": "3.27.4"
|
||||
"@tiptap/core": "3.28.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-strike": {
|
||||
"version": "3.27.4",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-strike/-/extension-strike-3.27.4.tgz",
|
||||
"integrity": "sha512-8OXwcPKuV3ToBBgyvDxH1jQdObK5FIKCGiyIim6qNWiOpi9BhM3XYD+aO1khjv8qIjtoI/DYbizF4ewj09fX2g==",
|
||||
"version": "3.28.0",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-strike/-/extension-strike-3.28.0.tgz",
|
||||
"integrity": "sha512-VVj2ZZU9QYqiHLcjqMqRYvuHSsokj/AgUl+6TzLrKjlWwyZ18D4H2vkyI0g70iVTKnUpZ3sEy8WA/rqjgBjqBg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.27.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-subscript": {
|
||||
"version": "3.27.4",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-subscript/-/extension-subscript-3.27.4.tgz",
|
||||
"integrity": "sha512-gs0AexP7GsE9vgdkwhqYgrKu7kD96PjmgCorsGLdA60m71eTavm6j8NN1m1nvcDPO1sTpP8ACs2mhipj+WS5Iw==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.27.4",
|
||||
"@tiptap/pm": "3.27.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-superscript": {
|
||||
"version": "3.27.4",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-superscript/-/extension-superscript-3.27.4.tgz",
|
||||
"integrity": "sha512-krlpnLeNBF6hVbQDrkuoXiy52v5YctoGPkLnxmftYNtloVrikRpgpetTRsFh0P6hLwv6g/g8SzoM23iMBB3S4A==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.27.4",
|
||||
"@tiptap/pm": "3.27.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-table": {
|
||||
"version": "3.27.4",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-table/-/extension-table-3.27.4.tgz",
|
||||
"integrity": "sha512-ejQjqt8GjUn4YswG/SsiLr/W3LZApZGUEDW0N7NoOduE0dBZ/pVJHPuqWu33kK+phJjSNCIN+bSAkoWE01rZSw==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.27.4",
|
||||
"@tiptap/pm": "3.27.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-table-cell": {
|
||||
"version": "3.27.4",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-table-cell/-/extension-table-cell-3.27.4.tgz",
|
||||
"integrity": "sha512-1B7J4ZiaXaGxT2IB3hrwtz0433bFVSWsDB+B125vt2DZQr9bgdX40GLesSPlymqOdMxKJwksCPMan2ON2LkVAg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/extension-table": "3.27.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-table-header": {
|
||||
"version": "3.27.4",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-table-header/-/extension-table-header-3.27.4.tgz",
|
||||
"integrity": "sha512-V/O690Z6VcHMAWDfgVFiOCwx3eE2/HM2gH+Fp0eQe3WnajQj2DPViW4VWR/rNVl3DspHoL/EU+eEsnhcvO34Vw==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/extension-table": "3.27.4"
|
||||
"@tiptap/core": "3.28.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-table-of-contents": {
|
||||
@@ -1768,82 +1664,56 @@
|
||||
"uuid": "dist/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-table-row": {
|
||||
"version": "3.27.4",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-table-row/-/extension-table-row-3.27.4.tgz",
|
||||
"integrity": "sha512-2RTJtcy90Tc2+HpW1JyKMTwg/zz4u6hHof4CTcJS/eXLk3g1L60DDzYvz4GzBxQvsOT3QVcbaU9QOk9A3Sx7Fg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/extension-table": "3.27.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-text": {
|
||||
"version": "3.27.4",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-text/-/extension-text-3.27.4.tgz",
|
||||
"integrity": "sha512-lKQH/hP4FBXsziHypd6Ywj8JFvMLM5GVkK1xsH6yApNuXbHq95rd42ZOYWpYILIBib7tlaz93z61d74UrJiuiw==",
|
||||
"version": "3.28.0",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-text/-/extension-text-3.28.0.tgz",
|
||||
"integrity": "sha512-Jqp1LgfY1mnp4TQHoy+vnHyfn6qnnAM6nHgGwbY5zA8b/Xf1Etll6pziTx9p1J1qcfAgSrnjOyAmA++H7VQqww==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.27.4"
|
||||
"@tiptap/core": "3.28.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-text-align": {
|
||||
"version": "3.27.4",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-text-align/-/extension-text-align-3.27.4.tgz",
|
||||
"integrity": "sha512-ArfL7GLOXCSmrmiBiaWwAf7RPHXDdxLGPru29qKDLQDthjXcNOdlwlPBbolRu7mXwlSmaYpqWGrG75/AEat3mw==",
|
||||
"version": "3.28.0",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-text-align/-/extension-text-align-3.28.0.tgz",
|
||||
"integrity": "sha512-P+KQMTtCpLFq9dRvy/fbyu2BGALulT/1HtsLbpFG4tKATaKa+cFnJ7rLZF7b3AdAMDNtXdnivxAtixAMBt2QWw==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.27.4"
|
||||
"@tiptap/core": "3.28.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-text-style": {
|
||||
"version": "3.27.4",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-text-style/-/extension-text-style-3.27.4.tgz",
|
||||
"integrity": "sha512-Wmj64TQXY85gc7lUNbubW32sDCnVOJlpGraMeARRC9Z0EKBX1JpAxddo/64F17bn3kzLxXVszBFyLRcNgTdU2g==",
|
||||
"version": "3.28.0",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-text-style/-/extension-text-style-3.28.0.tgz",
|
||||
"integrity": "sha512-UreMyqZSv770+CXJK/l1qeHUdaNMQAVkxSOPWpiY9FiT8B4OQyjA7WBOlWrzbvVTzfJvXWk2Y3SWgVRx+/Cd9A==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.27.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-typography": {
|
||||
"version": "3.27.4",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-typography/-/extension-typography-3.27.4.tgz",
|
||||
"integrity": "sha512-Sn4HZOKpcFR0m7msSGWNEunRobiXk8bs78e8+qJHa3yoxPfXsFoZySEgbD6TO7JjzQtVG927FQLCXQTzK7Q0Tg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.27.4"
|
||||
"@tiptap/core": "3.28.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-underline": {
|
||||
"version": "3.27.4",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-underline/-/extension-underline-3.27.4.tgz",
|
||||
"integrity": "sha512-nRJGvRyEXDtINlHTW+C2oWcL3vmX1URVxAPpkD3Zwn5Rb/vEeOU/pk/w97I0iid816MR4iVbvl1XhbUVegK9gQ==",
|
||||
"version": "3.28.0",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extension-underline/-/extension-underline-3.28.0.tgz",
|
||||
"integrity": "sha512-rwxCS6vTh2DJkNIYQX7JSrrRSmm76e2y48aZeuZO5ShkvLWMuJ3/zqDHRxAQVDiJhuE2Cp8NrTmPYlUc9YrT0A==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.27.4"
|
||||
"@tiptap/core": "3.28.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-unique-id": {
|
||||
@@ -1877,23 +1747,23 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extensions": {
|
||||
"version": "3.27.4",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extensions/-/extensions-3.27.4.tgz",
|
||||
"integrity": "sha512-d8opkg2iGtVwJmNGIqv0blfRxnvWOJp1brz+Z8CsP4ojSS2ZtaE46d6JSQ5OeJ7nMpjhT+9wh4UQcA7OSEO59w==",
|
||||
"version": "3.28.0",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/extensions/-/extensions-3.28.0.tgz",
|
||||
"integrity": "sha512-DJT1khCK+O/pT1gQlAnoKAx6zwDkgv7GtnhSfkqm1/4KHC3x+SSJnBIgBl9oGHymA+DxWbW1EULU4V3d/kT2uQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "3.27.4",
|
||||
"@tiptap/pm": "3.27.4"
|
||||
"@tiptap/core": "3.28.0",
|
||||
"@tiptap/pm": "3.28.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/pm": {
|
||||
"version": "3.27.4",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/pm/-/pm-3.27.4.tgz",
|
||||
"integrity": "sha512-UB8lcyomfWk7YGI2PZKNqcYXfyRA+PFj+QntlsUXyrsiA5JJIaE8SHKYjxKlGG/xtW3EtPm1b0p38T9Mk4xiFw==",
|
||||
"version": "3.28.0",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/pm/-/pm-3.28.0.tgz",
|
||||
"integrity": "sha512-ALcpwZMUdat9gjJKlpscpoqXStoLhU246LPEVBDvJdIsoUKvUu3MrzfXik2Y8mtSGfhjtm9O2TRkWxQiFVMwsQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-changeset": "^2.4.1",
|
||||
@@ -1916,35 +1786,35 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/starter-kit": {
|
||||
"version": "3.27.4",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/starter-kit/-/starter-kit-3.27.4.tgz",
|
||||
"integrity": "sha512-/sb6rFxNt5BO4hWpUwvHh+Yh1kNyCQuuz3oDpGef5HUUjSdu9p9rfNiHWIUKBadK8VXuw5es7N+UlZ4hma+gvA==",
|
||||
"version": "3.28.0",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/starter-kit/-/starter-kit-3.28.0.tgz",
|
||||
"integrity": "sha512-pqvFpValV+ONtlu3l4s73ROm/tEjoGMmt6uHmSJaLbqTcMHkdWuR3flJ/5brr4IDHe1foxmNicMbRxlje7yBYw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@tiptap/core": "^3.27.4",
|
||||
"@tiptap/extension-blockquote": "^3.27.4",
|
||||
"@tiptap/extension-bold": "^3.27.4",
|
||||
"@tiptap/extension-bullet-list": "^3.27.4",
|
||||
"@tiptap/extension-code": "^3.27.4",
|
||||
"@tiptap/extension-code-block": "^3.27.4",
|
||||
"@tiptap/extension-document": "^3.27.4",
|
||||
"@tiptap/extension-dropcursor": "^3.27.4",
|
||||
"@tiptap/extension-gapcursor": "^3.27.4",
|
||||
"@tiptap/extension-hard-break": "^3.27.4",
|
||||
"@tiptap/extension-heading": "^3.27.4",
|
||||
"@tiptap/extension-horizontal-rule": "^3.27.4",
|
||||
"@tiptap/extension-italic": "^3.27.4",
|
||||
"@tiptap/extension-link": "^3.27.4",
|
||||
"@tiptap/extension-list": "^3.27.4",
|
||||
"@tiptap/extension-list-item": "^3.27.4",
|
||||
"@tiptap/extension-list-keymap": "^3.27.4",
|
||||
"@tiptap/extension-ordered-list": "^3.27.4",
|
||||
"@tiptap/extension-paragraph": "^3.27.4",
|
||||
"@tiptap/extension-strike": "^3.27.4",
|
||||
"@tiptap/extension-text": "^3.27.4",
|
||||
"@tiptap/extension-underline": "^3.27.4",
|
||||
"@tiptap/extensions": "^3.27.4",
|
||||
"@tiptap/pm": "^3.27.4"
|
||||
"@tiptap/core": "^3.28.0",
|
||||
"@tiptap/extension-blockquote": "^3.28.0",
|
||||
"@tiptap/extension-bold": "^3.28.0",
|
||||
"@tiptap/extension-bullet-list": "^3.28.0",
|
||||
"@tiptap/extension-code": "^3.28.0",
|
||||
"@tiptap/extension-code-block": "^3.28.0",
|
||||
"@tiptap/extension-document": "^3.28.0",
|
||||
"@tiptap/extension-dropcursor": "^3.28.0",
|
||||
"@tiptap/extension-gapcursor": "^3.28.0",
|
||||
"@tiptap/extension-hard-break": "^3.28.0",
|
||||
"@tiptap/extension-heading": "^3.28.0",
|
||||
"@tiptap/extension-horizontal-rule": "^3.28.0",
|
||||
"@tiptap/extension-italic": "^3.28.0",
|
||||
"@tiptap/extension-link": "^3.28.0",
|
||||
"@tiptap/extension-list": "^3.28.0",
|
||||
"@tiptap/extension-list-item": "^3.28.0",
|
||||
"@tiptap/extension-list-keymap": "^3.28.0",
|
||||
"@tiptap/extension-ordered-list": "^3.28.0",
|
||||
"@tiptap/extension-paragraph": "^3.28.0",
|
||||
"@tiptap/extension-strike": "^3.28.0",
|
||||
"@tiptap/extension-text": "^3.28.0",
|
||||
"@tiptap/extension-underline": "^3.28.0",
|
||||
"@tiptap/extensions": "^3.28.0",
|
||||
"@tiptap/pm": "^3.28.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
@@ -1966,22 +1836,22 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/vue-3": {
|
||||
"version": "3.27.4",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/vue-3/-/vue-3-3.27.4.tgz",
|
||||
"integrity": "sha512-fTz21viWZlpZz7PPdHJde+kzYmgRXBivVLoC2KGEeltqsREa8JR0v/eUDbzeMjj6AIajlNDtmn96I3h14gZJLg==",
|
||||
"version": "3.28.0",
|
||||
"resolved": "https://registry.npmmirror.com/@tiptap/vue-3/-/vue-3-3.28.0.tgz",
|
||||
"integrity": "sha512-twb3T6hofM0ajncCSgrLYIjfn86WfR2NVXteurdNOcnkJCIMTij5OhO/xn0z7y8+lp3TMkF6H5kajUpivBpnzw==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@tiptap/extension-bubble-menu": "^3.27.4",
|
||||
"@tiptap/extension-floating-menu": "^3.27.4"
|
||||
"@tiptap/extension-bubble-menu": "^3.28.0",
|
||||
"@tiptap/extension-floating-menu": "^3.28.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@floating-ui/dom": "^1.0.0",
|
||||
"@tiptap/core": "3.27.4",
|
||||
"@tiptap/pm": "3.27.4",
|
||||
"@tiptap/core": "3.28.0",
|
||||
"@tiptap/pm": "3.28.0",
|
||||
"vue": "^3.0.0"
|
||||
}
|
||||
},
|
||||
@@ -7229,7 +7099,7 @@
|
||||
"version": "5.9.3",
|
||||
"resolved": "https://registry.npmmirror.com/typescript/-/typescript-5.9.3.tgz",
|
||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||
"devOptional": true,
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
|
||||
@@ -11,6 +11,14 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "^2.3.2",
|
||||
"@tiptap/extension-color": "^3.28.0",
|
||||
"@tiptap/extension-image": "^3.28.0",
|
||||
"@tiptap/extension-link": "^3.28.0",
|
||||
"@tiptap/extension-text-align": "^3.28.0",
|
||||
"@tiptap/extension-text-style": "^3.28.0",
|
||||
"@tiptap/extension-underline": "^3.28.0",
|
||||
"@tiptap/starter-kit": "^3.28.0",
|
||||
"@tiptap/vue-3": "^3.28.0",
|
||||
"@umoteam/editor": "^10.2.1",
|
||||
"axios": "^1.13.1",
|
||||
"chart": "^0.1.2",
|
||||
|
||||
@@ -379,9 +379,9 @@ onMounted(async () => {
|
||||
.welcome-section {
|
||||
margin-bottom: 16px;
|
||||
padding: 32px;
|
||||
background: linear-gradient(135deg, #3973ff 0%, #4f84ff 100%);
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 4px 12px rgba(6, 45, 163, 0.2);
|
||||
box-shadow: 0 4px 20px rgba(102, 126, 234, 0.25);
|
||||
|
||||
.welcome-content {
|
||||
.welcome-title {
|
||||
@@ -408,63 +408,65 @@ onMounted(async () => {
|
||||
|
||||
.stat-card {
|
||||
background: var(--el-bg-color);
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
border-radius: 16px;
|
||||
padding: 28px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
gap: 20px;
|
||||
border: 1px solid var(--el-border-color-lighter);
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
|
||||
transition: all 0.3s;
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
|
||||
transition: all 0.3s ease;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-4px);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
||||
transform: translateY(-6px);
|
||||
box-shadow: 0 12px 24px rgba(0, 0, 0, 0.12);
|
||||
border-color: var(--el-color-primary-light-7);
|
||||
}
|
||||
|
||||
.stat-icon-wrapper {
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
border-radius: 12px;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border-radius: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
|
||||
|
||||
.el-icon {
|
||||
color: #fff;
|
||||
font-size: 28px;
|
||||
}
|
||||
}
|
||||
|
||||
&.income .stat-icon-wrapper {
|
||||
background: linear-gradient(135deg, #3973ff 0%, #4f84ff 100%);
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
}
|
||||
|
||||
&.users .stat-icon-wrapper {
|
||||
background: linear-gradient(135deg, #10b981 0%, #34d399 100%);
|
||||
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
|
||||
}
|
||||
|
||||
&.orders .stat-icon-wrapper {
|
||||
background: linear-gradient(135deg, #f59e0b 0%, #fbbf24 100%);
|
||||
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
|
||||
}
|
||||
|
||||
&.active .stat-icon-wrapper {
|
||||
background: linear-gradient(135deg, #8b5cf6 0%, #a78bfa 100%);
|
||||
background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);
|
||||
}
|
||||
|
||||
&.knowledge .stat-icon-wrapper {
|
||||
background: linear-gradient(135deg, #3973ff 0%, #4f84ff 100%);
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
}
|
||||
|
||||
&.employees .stat-icon-wrapper {
|
||||
background: linear-gradient(135deg, #10b981 0%, #34d399 100%);
|
||||
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
|
||||
}
|
||||
|
||||
&.tenants .stat-icon-wrapper {
|
||||
background: linear-gradient(135deg, #8b5cf6 0%, #a78bfa 100%);
|
||||
background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);
|
||||
}
|
||||
|
||||
.stat-content {
|
||||
@@ -692,15 +694,16 @@ onMounted(async () => {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #fff;
|
||||
font-weight: 500;
|
||||
|
||||
&.operation {
|
||||
background-color: rgba(79, 132, 255, 0.2);
|
||||
color: #4f84ff;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
&.access {
|
||||
background-color: rgba(85, 190, 130, 0.2);
|
||||
color: #55be82;
|
||||
background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,14 +29,14 @@ export default defineConfig({
|
||||
server: {
|
||||
host: "127.0.0.1",
|
||||
port: 4000,
|
||||
// 开发时前端在 5000,接口走相对路径 /platform/*、/backend/*,转发到本地 Go(当前 httpport=8081)
|
||||
// 开发时前端在 4000,接口走相对路径 /platform/*、/backend/*,转发到本地 Go(当前 httpport=9000)
|
||||
proxy: {
|
||||
"/platform": {
|
||||
target: "http://127.0.0.1:8081",
|
||||
target: "http://127.0.0.1:9000",
|
||||
changeOrigin: true,
|
||||
},
|
||||
"/backend": {
|
||||
target: "http://127.0.0.1:8081",
|
||||
target: "http://127.0.0.1:9000",
|
||||
changeOrigin: true,
|
||||
},
|
||||
},
|
||||
|
||||
+11
-6
@@ -1,13 +1,13 @@
|
||||
{
|
||||
"name" : "uniapp",
|
||||
"appid" : "",
|
||||
"appid" : "__UNI__D80959E",
|
||||
"description" : "",
|
||||
"versionName" : "1.0.0",
|
||||
"versionCode" : "100",
|
||||
"transformPx" : false,
|
||||
"uniStatistics": {
|
||||
"enable": false,
|
||||
"debug": false
|
||||
"uniStatistics" : {
|
||||
"enable" : false,
|
||||
"debug" : false
|
||||
},
|
||||
/* 5+App特有相关 */
|
||||
"app-plus" : {
|
||||
@@ -57,7 +57,9 @@
|
||||
"mp-weixin" : {
|
||||
"appid" : "",
|
||||
"setting" : {
|
||||
"urlCheck" : false
|
||||
"urlCheck" : false,
|
||||
"minified" : true,
|
||||
"postcss" : true
|
||||
},
|
||||
"usingComponents" : true,
|
||||
"mergeVirtualHostAttributes" : true
|
||||
@@ -74,5 +76,8 @@
|
||||
"usingComponents" : true,
|
||||
"mergeVirtualHostAttributes" : true
|
||||
},
|
||||
"vueVersion" : "3"
|
||||
"vueVersion" : "3",
|
||||
"h5" : {
|
||||
"title" : "云泽系统"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,8 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view class="header">
|
||||
<view class="header-row">
|
||||
<view class="user-info">
|
||||
<text class="greeting">{{ greeting }}</text>
|
||||
<text class="username">{{ user?.nickname || '云泽用户' }}</text>
|
||||
</view>
|
||||
<view class="avatar">
|
||||
<text class="avatar-text">{{ avatarText }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="search-bar">
|
||||
<FaIcon name="magnifying-glass" color="#909399" :size="16" />
|
||||
<FaIcon name="magnifying-glass" color="#ffffff" :size="16" />
|
||||
<text class="search-text">搜索功能、数据...</text>
|
||||
</view>
|
||||
</view>
|
||||
@@ -84,18 +75,6 @@ import AppTabbar from '@/components/AppTabbar.vue'
|
||||
|
||||
const user = ref(null)
|
||||
|
||||
const greeting = computed(() => {
|
||||
const hour = new Date().getHours()
|
||||
if (hour < 12) return '早上好'
|
||||
if (hour < 18) return '下午好'
|
||||
return '晚上好'
|
||||
})
|
||||
|
||||
const avatarText = computed(() => {
|
||||
const name = user.value?.nickname || '云'
|
||||
return name.charAt(0).toUpperCase()
|
||||
})
|
||||
|
||||
const noteCount = ref(0)
|
||||
const scheduleCount = ref(0)
|
||||
const schedulePending = ref(0)
|
||||
@@ -199,60 +178,25 @@ function onActivityTap(item) {
|
||||
|
||||
.header {
|
||||
flex-shrink: 0;
|
||||
padding: calc(var(--status-bar-height, 44px) + 20rpx) $page-padding-x 24rpx;
|
||||
background: $color-card;
|
||||
box-shadow: $shadow-header;
|
||||
}
|
||||
|
||||
.header-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 28rpx;
|
||||
}
|
||||
|
||||
.greeting {
|
||||
display: block;
|
||||
font-size: 26rpx;
|
||||
color: $color-text-muted;
|
||||
}
|
||||
|
||||
.username {
|
||||
display: block;
|
||||
font-size: 40rpx;
|
||||
font-weight: 600;
|
||||
color: $color-text;
|
||||
margin-top: 4rpx;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: 88rpx;
|
||||
height: 88rpx;
|
||||
border-radius: 50%;
|
||||
background: $color-primary-bg;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.avatar-text {
|
||||
font-size: 34rpx;
|
||||
font-weight: 600;
|
||||
color: $color-primary;
|
||||
padding: calc(var(--status-bar-height, 44px) + 20rpx) $page-padding-x 20rpx;
|
||||
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
|
||||
box-shadow: 0 4rpx 16rpx rgba(79, 172, 254, 0.15);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.search-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
background: $color-bg-page;
|
||||
border-radius: $radius-md;
|
||||
padding: 20rpx 24rpx;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
border-radius: $radius-full;
|
||||
padding: 16rpx 24rpx;
|
||||
border: 1rpx solid rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
.search-text {
|
||||
font-size: 28rpx;
|
||||
color: $color-text-muted;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
.main-scroll {
|
||||
@@ -344,8 +288,14 @@ function onActivityTap(item) {
|
||||
}
|
||||
|
||||
.quick-icon {
|
||||
@include icon-box(88rpx);
|
||||
border-radius: $radius-lg;
|
||||
width: 88rpx;
|
||||
height: 88rpx;
|
||||
border-radius: 12rpx;
|
||||
background: linear-gradient(135deg, rgba(79, 172, 254, 0.15) 0%, rgba(0, 242, 254, 0.15) 100%);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.quick-name {
|
||||
|
||||
@@ -242,7 +242,7 @@ function onItemTap(item) {
|
||||
transform: translateY(-50%);
|
||||
width: 6rpx;
|
||||
height: 36rpx;
|
||||
background: $color-primary;
|
||||
background: linear-gradient(180deg, #4facfe 0%, #00f2fe 100%);
|
||||
border-radius: 0 4rpx 4rpx 0;
|
||||
}
|
||||
}
|
||||
@@ -270,10 +270,10 @@ function onItemTap(item) {
|
||||
border-radius: $radius-md;
|
||||
|
||||
&.active {
|
||||
background: $color-primary-bg;
|
||||
background: linear-gradient(135deg, rgba(79, 172, 254, 0.08) 0%, rgba(0, 242, 254, 0.08) 100%);
|
||||
|
||||
.item-name {
|
||||
color: $color-primary;
|
||||
color: #4facfe;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="main-scroll">
|
||||
<view class="main-scroll" style="margin-top:10rpx">
|
||||
<view class="menu-group" v-for="(group, gIndex) in menuGroups" :key="gIndex">
|
||||
<view
|
||||
class="menu-item"
|
||||
@@ -167,26 +167,55 @@ function handleLogout() {
|
||||
|
||||
.profile-header {
|
||||
flex-shrink: 0;
|
||||
padding: calc(var(--status-bar-height, 44px) + 20rpx) $page-padding-x 36rpx;
|
||||
background: $color-primary;
|
||||
padding: calc(var(--status-bar-height, 44px) + 24rpx) $page-padding-x 40rpx;
|
||||
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.profile-header::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -50%;
|
||||
right: -50%;
|
||||
width: 400rpx;
|
||||
height: 400rpx;
|
||||
border-radius: 50%;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.profile-header::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: -30%;
|
||||
left: -20%;
|
||||
width: 350rpx;
|
||||
height: 350rpx;
|
||||
border-radius: 50%;
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.profile-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 24rpx;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.profile-avatar {
|
||||
width: 112rpx;
|
||||
height: 112rpx;
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
border-radius: 50%;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
border: 4rpx solid rgba(255, 255, 255, 0.35);
|
||||
background: linear-gradient(135deg, rgba(255, 255, 255, 0.25) 0%, rgba(255, 255, 255, 0.15) 100%);
|
||||
border: 3rpx solid rgba(255, 255, 255, 0.4);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
box-shadow: 0 12rpx 32rpx rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.avatar-text {
|
||||
@@ -231,9 +260,11 @@ function handleLogout() {
|
||||
.profile-stats {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
margin-top: 36rpx;
|
||||
padding-top: 28rpx;
|
||||
margin-top: 40rpx;
|
||||
padding-top: 32rpx;
|
||||
border-top: 1rpx solid rgba(255, 255, 255, 0.2);
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.profile-stat {
|
||||
@@ -263,13 +294,21 @@ function handleLogout() {
|
||||
@include card;
|
||||
margin-bottom: 24rpx;
|
||||
overflow: hidden;
|
||||
border-radius: 16rpx;
|
||||
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
|
||||
transition: box-shadow 0.3s ease;
|
||||
}
|
||||
|
||||
.menu-group:active {
|
||||
box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 28rpx 24rpx;
|
||||
padding: 32rpx 28rpx;
|
||||
transition: background 0.2s ease, transform 0.2s ease;
|
||||
|
||||
& + & {
|
||||
border-top: 1rpx solid $color-divider;
|
||||
@@ -277,6 +316,7 @@ function handleLogout() {
|
||||
|
||||
&:active {
|
||||
background: $color-bg-page;
|
||||
transform: translateX(4rpx);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -289,11 +329,19 @@ function handleLogout() {
|
||||
}
|
||||
|
||||
.menu-icon {
|
||||
@include icon-box(64rpx);
|
||||
width: 56rpx;
|
||||
height: 56rpx;
|
||||
border-radius: 12rpx;
|
||||
background: linear-gradient(135deg, rgba(79, 172, 254, 0.1) 0%, rgba(0, 242, 254, 0.1) 100%);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.menu-title {
|
||||
font-size: 28rpx;
|
||||
font-size: 30rpx;
|
||||
font-weight: 500;
|
||||
color: $color-text;
|
||||
}
|
||||
|
||||
@@ -306,31 +354,39 @@ function handleLogout() {
|
||||
|
||||
.menu-badge {
|
||||
font-size: 20rpx;
|
||||
font-weight: 600;
|
||||
color: #ffffff;
|
||||
background: $color-primary;
|
||||
padding: 4rpx 12rpx;
|
||||
border-radius: $radius-full;
|
||||
min-width: 32rpx;
|
||||
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
|
||||
padding: 6rpx 14rpx;
|
||||
border-radius: 12rpx;
|
||||
min-width: 36rpx;
|
||||
text-align: center;
|
||||
line-height: 1.4;
|
||||
box-shadow: 0 4rpx 12rpx rgba(79, 172, 254, 0.3);
|
||||
}
|
||||
|
||||
.logout-btn {
|
||||
@include card;
|
||||
height: 96rpx;
|
||||
height: 100rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 8rpx;
|
||||
margin-bottom: 12rpx;
|
||||
border-radius: 16rpx;
|
||||
background: linear-gradient(135deg, rgba(245, 108, 108, 0.1) 0%, rgba(245, 108, 108, 0.05) 100%);
|
||||
border: 1rpx solid rgba(245, 108, 108, 0.2);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.logout-btn-hover {
|
||||
background: $color-bg-page !important;
|
||||
background: linear-gradient(135deg, rgba(245, 108, 108, 0.2) 0%, rgba(245, 108, 108, 0.1) 100%) !important;
|
||||
box-shadow: 0 4rpx 16rpx rgba(245, 108, 108, 0.15) !important;
|
||||
}
|
||||
|
||||
.logout-text {
|
||||
font-size: 30rpx;
|
||||
color: $color-text-secondary;
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #f56c6c;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
|
||||
<view class="field content-field">
|
||||
<text class="field-label">内容</text>
|
||||
<view class="editor-wrap">
|
||||
<editor
|
||||
id="noteEditor"
|
||||
class="note-editor"
|
||||
@@ -23,21 +22,7 @@
|
||||
:value="form.content"
|
||||
@ready="onEditorReady"
|
||||
@input="onEditorInput"
|
||||
@focus="editorFocused = true"
|
||||
@blur="editorFocused = false"
|
||||
/>
|
||||
<view class="editor-toolbar">
|
||||
<view
|
||||
v-for="btn in toolbarBtns"
|
||||
:key="btn.name"
|
||||
class="toolbar-btn"
|
||||
:class="{ active: btn.active }"
|
||||
@tap="execCommand(btn)"
|
||||
>
|
||||
<text>{{ btn.label }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="switch-row" @tap="form.pinned = !form.pinned">
|
||||
@@ -71,7 +56,6 @@ import { formatDate } from '@/utils/date.js'
|
||||
const noteId = ref('')
|
||||
const saving = ref(false)
|
||||
const editorCtx = ref(null)
|
||||
const editorFocused = ref(false)
|
||||
const form = reactive({
|
||||
title: '',
|
||||
content: '',
|
||||
@@ -81,28 +65,6 @@ const meta = reactive({
|
||||
updatedAt: 0
|
||||
})
|
||||
|
||||
const toolbarBtns = reactive([
|
||||
{ name: 'bold', label: 'B', active: false, value: 'bold' },
|
||||
{ name: 'italic', label: 'I', active: false, value: 'italic' },
|
||||
{ name: 'underline', label: 'U', active: false, value: 'underline' },
|
||||
{ name: 'strike', label: 'S', active: false, value: 'strikeThrough' },
|
||||
{ name: 'header', label: 'H', active: false, value: 'header' },
|
||||
{ name: 'list', label: '•', active: false, value: 'insertUnorderedList' },
|
||||
{ name: 'indent', label: '→', active: false, value: 'indent' },
|
||||
{ name: 'outdent', label: '←', active: false, value: 'outdent' },
|
||||
{ name: 'divider', label: '—', active: false, value: 'insertHorizontalRule' },
|
||||
])
|
||||
|
||||
onLoad(async (query) => {
|
||||
if (query?.id) {
|
||||
noteId.value = query.id
|
||||
uni.setNavigationBarTitle({ title: '编辑笔记' })
|
||||
await loadNote(query.id)
|
||||
} else {
|
||||
uni.setNavigationBarTitle({ title: '新建笔记' })
|
||||
}
|
||||
})
|
||||
|
||||
function onEditorReady() {
|
||||
uni.createSelectorQuery().select('#noteEditor').context((res) => {
|
||||
if (res && res.context) {
|
||||
@@ -118,14 +80,15 @@ function onEditorInput(e) {
|
||||
form.content = e.detail.html || ''
|
||||
}
|
||||
|
||||
function execCommand(btn) {
|
||||
if (!editorCtx.value) return
|
||||
if (btn.name === 'header') {
|
||||
editorCtx.value.format('header', 'H2')
|
||||
onLoad(async (query) => {
|
||||
if (query?.id) {
|
||||
noteId.value = query.id
|
||||
uni.setNavigationBarTitle({ title: '编辑笔记' })
|
||||
await loadNote(query.id)
|
||||
} else {
|
||||
editorCtx.value.format(btn.value)
|
||||
uni.setNavigationBarTitle({ title: '新建笔记' })
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
async function loadNote(id) {
|
||||
try {
|
||||
@@ -246,17 +209,9 @@ function onDelete() {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding-bottom: 0;
|
||||
padding: 24rpx 28rpx 0 28rpx;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.editor-wrap {
|
||||
background: $color-bg-page;
|
||||
border-radius: $radius-md;
|
||||
overflow: hidden;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-top: 1rpx solid $color-divider;
|
||||
}
|
||||
|
||||
.note-editor {
|
||||
@@ -268,32 +223,8 @@ function onDelete() {
|
||||
color: $color-text;
|
||||
box-sizing: border-box;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.editor-toolbar {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8rpx;
|
||||
padding: 16rpx 20rpx;
|
||||
border-top: 1rpx solid $color-divider;
|
||||
background: $color-card;
|
||||
}
|
||||
|
||||
.toolbar-btn {
|
||||
padding: 10rpx 20rpx;
|
||||
border-radius: $radius-sm;
|
||||
font-size: 24rpx;
|
||||
color: $color-text-secondary;
|
||||
background: $color-bg-page;
|
||||
|
||||
&.active {
|
||||
color: $color-primary;
|
||||
background: $color-primary-bg;
|
||||
}
|
||||
|
||||
&:active {
|
||||
opacity: 0.7;
|
||||
}
|
||||
border-radius: $radius-md;
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
|
||||
@@ -65,6 +65,38 @@
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
|
||||
<view class="field">
|
||||
<text class="field-label">重复提醒间隔(分钟)</text>
|
||||
<view class="number-input">
|
||||
<button class="number-btn" @tap="form.repeatIntervalMinutes = Math.max(0, form.repeatIntervalMinutes - 1)" :disabled="isCompleted">−</button>
|
||||
<input
|
||||
v-model.number="form.repeatIntervalMinutes"
|
||||
type="number"
|
||||
class="number-field"
|
||||
:disabled="isCompleted"
|
||||
@blur="form.repeatIntervalMinutes = Math.max(0, Math.min(1440, form.repeatIntervalMinutes))"
|
||||
/>
|
||||
<button class="number-btn" @tap="form.repeatIntervalMinutes = Math.min(1440, form.repeatIntervalMinutes + 1)" :disabled="isCompleted">+</button>
|
||||
</view>
|
||||
<text class="form-tip">0表示不重复,仅发送一次</text>
|
||||
</view>
|
||||
|
||||
<view class="field">
|
||||
<text class="field-label">最多提醒次数</text>
|
||||
<view class="number-input">
|
||||
<button class="number-btn" @tap="form.maxSendCount = Math.max(1, form.maxSendCount - 1)" :disabled="isCompleted">−</button>
|
||||
<input
|
||||
v-model.number="form.maxSendCount"
|
||||
type="number"
|
||||
class="number-field"
|
||||
:disabled="isCompleted"
|
||||
@blur="form.maxSendCount = Math.max(1, Math.min(100, form.maxSendCount))"
|
||||
/>
|
||||
<button class="number-btn" @tap="form.maxSendCount = Math.min(100, form.maxSendCount + 1)" :disabled="isCompleted">+</button>
|
||||
</view>
|
||||
<text class="form-tip">最多发送的提醒次数</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="!isCompleted" class="footer">
|
||||
@@ -99,7 +131,9 @@ const form = reactive({
|
||||
date: '',
|
||||
time: '',
|
||||
remindChannels: ['app'],
|
||||
remindMinutes: 15
|
||||
remindMinutes: 0,
|
||||
repeatIntervalMinutes: 0,
|
||||
maxSendCount: 1
|
||||
})
|
||||
|
||||
const remindIndex = computed(() => {
|
||||
@@ -134,7 +168,9 @@ async function loadSchedule(id) {
|
||||
form.date = formatDate(d)
|
||||
form.time = `${pad(d.getHours())}:${pad(d.getMinutes())}`
|
||||
form.remindChannels = [...(item.remindChannels || [])]
|
||||
form.remindMinutes = item.remindMinutes ?? 15
|
||||
form.remindMinutes = item.remindMinutes ?? 0
|
||||
form.repeatIntervalMinutes = item.repeatIntervalMinutes ?? 0
|
||||
form.maxSendCount = item.maxSendCount ?? 1
|
||||
isCompleted.value = !!item.completed
|
||||
} catch (e) {
|
||||
uni.showToast({ title: '加载失败', icon: 'none' })
|
||||
@@ -200,7 +236,9 @@ async function saveData(datetime) {
|
||||
content: form.content,
|
||||
datetime,
|
||||
remindChannels: [...form.remindChannels],
|
||||
remindMinutes: form.remindMinutes
|
||||
remindMinutes: form.remindMinutes,
|
||||
repeatIntervalMinutes: form.repeatIntervalMinutes,
|
||||
maxSendCount: form.maxSendCount
|
||||
}
|
||||
try {
|
||||
if (scheduleId.value) {
|
||||
@@ -334,6 +372,60 @@ async function saveData(datetime) {
|
||||
}
|
||||
}
|
||||
|
||||
.number-input {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12rpx;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.number-btn {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
border-radius: $radius-md;
|
||||
background: $color-bg-page;
|
||||
border: 1rpx solid $color-divider;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 28rpx;
|
||||
color: $color-text;
|
||||
flex-shrink: 0;
|
||||
|
||||
&:active:not(:disabled) {
|
||||
background: $color-primary-bg;
|
||||
color: $color-primary;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
.number-field {
|
||||
flex: 1;
|
||||
height: 60rpx;
|
||||
padding: 0 16rpx;
|
||||
background: $color-bg-page;
|
||||
border: 1rpx solid $color-divider;
|
||||
border-radius: $radius-md;
|
||||
font-size: 28rpx;
|
||||
color: $color-text;
|
||||
text-align: center;
|
||||
|
||||
&:disabled {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
.form-tip {
|
||||
display: block;
|
||||
font-size: 22rpx;
|
||||
color: $color-text-muted;
|
||||
margin-top: 8rpx;
|
||||
}
|
||||
|
||||
.footer {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// 标准商务主题(单色蓝 + 灰阶,无渐变)
|
||||
$color-primary: #3c9cff;
|
||||
$color-primary-dark: #2b8ae8;
|
||||
$color-primary-bg: #ecf5ff;
|
||||
// 标准商务主题(蓝色系 + 灰阶)
|
||||
$color-primary: #4facfe;
|
||||
$color-primary-dark: #00f2fe;
|
||||
$color-primary-bg: #e0f7ff;
|
||||
$color-bg-page: #f5f7fa;
|
||||
$color-card: #ffffff;
|
||||
$color-text: #303133;
|
||||
|
||||
+8
-21
@@ -1,29 +1,16 @@
|
||||
import { defineConfig, loadEnv } from 'vite'
|
||||
import uni from '@dcloudio/vite-plugin-uni'
|
||||
import { defineConfig } from 'vite'
|
||||
import uni from '@dcloudio/vite-plugin-uni'
|
||||
|
||||
export default defineConfig(({ mode }) => {
|
||||
const env = loadEnv(mode, process.cwd(), '')
|
||||
const apiTarget = (env.VITE_API_BASE_URL || 'http://localhost:9000').replace(/\/$/, '')
|
||||
|
||||
return {
|
||||
plugins: [uni()],
|
||||
server: {
|
||||
proxy: {
|
||||
// 勿用 /api:会与 uniapp/api/ 源码目录冲突,导致 request.js 等模块 404
|
||||
'/proxy-api': {
|
||||
target: apiTarget,
|
||||
changeOrigin: true,
|
||||
rewrite: (path) => path.replace(/^\/proxy-api/, '')
|
||||
}
|
||||
}
|
||||
},
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
uni()
|
||||
],
|
||||
css: {
|
||||
preprocessorOptions: {
|
||||
scss: {
|
||||
// 关闭废弃 API 警告
|
||||
silenceDeprecations: ['legacy-js-api', 'color-functions', 'import']
|
||||
silenceDeprecations: ['legacy-js-api', 'color-functions', 'import'],
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user