From 0c6efc4160243699975ae880b93379818fdf44ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=89=AB=E5=9C=B0=E5=83=A7?= <357099073@qq.com> Date: Tue, 3 Nov 2026 09:00:29 +0800 Subject: [PATCH] =?UTF-8?q?wizhi=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go/controllers/app_password_store.go | 243 + go/routers/api/api.go | 5 + platform/src/views/login/index.vue | 5 - uniapp/api/passwordStore.js | 77 + uniapp/components/NoteRichEditor.vue | 70 +- uniapp/pages.json | 952 +- uniapp/pages/login/login.vue | 696 +- uniapp/pages/nav/nav.vue | 132 +- uniapp/pages/tools/account/edit.vue | 399 + uniapp/pages/tools/account/index.vue | 388 + uniapp/pages/tools/schedule/reminder-edit.vue | 377 + uniapp/pages/tools/schedule/reminder.vue | 269 +- uniapp/pnpm-lock.yaml | 8981 +++++++++++++++++ uniapp/src/styles/rich-content.scss | 11 +- uniapp/utils/nav.js | 2 + uniapp/utils/table-editor.js | 14 + 16 files changed, 11810 insertions(+), 811 deletions(-) create mode 100644 go/controllers/app_password_store.go create mode 100644 uniapp/api/passwordStore.js create mode 100644 uniapp/pages/tools/account/edit.vue create mode 100644 uniapp/pages/tools/account/index.vue create mode 100644 uniapp/pages/tools/schedule/reminder-edit.vue create mode 100644 uniapp/pnpm-lock.yaml diff --git a/go/controllers/app_password_store.go b/go/controllers/app_password_store.go new file mode 100644 index 0000000..92c0a71 --- /dev/null +++ b/go/controllers/app_password_store.go @@ -0,0 +1,243 @@ +package controllers + +import ( + "strconv" + "strings" + + "server/middleware" + "server/models" + "server/pkg/identity" + "server/pkg/jwtutil" + + "github.com/beego/beego/v2/client/orm" + "github.com/beego/beego/v2/core/logs" + beego "github.com/beego/beego/v2/server/web" +) + +// ==================== 移动端 PasswordStore ==================== +// +// 移动端「账号管理」(密码库)接口。与 Web 端 /backend/passwordStore 同一套数据 +// (yz_backend_password_store,一个平台下挂多个账号),按 JWT 中的 tid + user_id +// 隔离,小程序「账号管理」页面调用。 + +type AppPasswordStoreController struct { + beego.Controller +} + +// 只放行移动端与租户端令牌:/api/** 仅被 uniapp 调用,平台令牌不该能打移动端接口。 +func (c *AppPasswordStoreController) appPwdClaims() (*jwtutil.Claims, error) { + claims, err := identity.Claims(c.Ctx.Request.Header.Get("Authorization"), identity.EndApp, identity.EndBackend) + if err != nil { + return nil, err + } + if claims.UserID <= 0 || claims.TenantId <= 0 { + return nil, orm.ErrNoRows + } + return claims, nil +} + +// GetList GET /api/passwordStore/list?keyword= +func (c *AppPasswordStoreController) GetList() { + cl, e := c.appPwdClaims() + if e != nil { + passwordReply(&c.Controller, 401, "未登录或无权限", nil) + return + } + qs := models.Orm.QueryTable(new(models.BackendPasswordStore)). + Filter("is_deleted", 0).Filter("tid", cl.TenantId).Filter("user_id", cl.UserID) + if k := strings.TrimSpace(c.GetString("keyword")); k != "" { + cond := orm.NewCondition(). + Or("platform__icontains", k). + Or("url__icontains", k). + Or("accounts__icontains", k). + Or("remark__icontains", k) + qs = qs.SetCond(orm.NewCondition().And("is_deleted", 0).And("tid", cl.TenantId).And("user_id", cl.UserID).AndCond(cond)) + } + var rows []models.BackendPasswordStore + if _, e = qs.OrderBy("-id").All(&rows); e != nil && e != orm.ErrNoRows { + logs.Error("[passwordStore] app list failed: %v", e) + passwordReply(&c.Controller, 500, "查询失败: "+e.Error(), nil) + return + } + res := make([]PasswordStoreItemDTO, 0, len(rows)) + for _, row := range rows { + res = append(res, PasswordStoreItemDTO{ + ID: row.ID, Tid: row.Tid, Platform: row.Platform, URL: row.URL, + Accounts: accountsFromJSON(row.Accounts), Remark: row.Remark, + UserID: row.UserID, CreateTime: row.CreateTime, UpdateTime: row.UpdateTime, + }) + } + passwordReply(&c.Controller, 200, "success", map[string]interface{}{"list": res, "total": len(res)}) +} + +// GetDetail GET /api/passwordStore/detail/:id +func (c *AppPasswordStoreController) GetDetail() { + cl, e := c.appPwdClaims() + if e != nil { + passwordReply(&c.Controller, 401, "未登录或无权限", nil) + return + } + id, e := strconv.Atoi(c.Ctx.Input.Param(":id")) + if e != nil { + passwordReply(&c.Controller, 400, "参数错误", nil) + return + } + var m models.BackendPasswordStore + e = models.Orm.QueryTable(new(models.BackendPasswordStore)). + Filter("id", id).Filter("is_deleted", 0).Filter("tid", cl.TenantId).Filter("user_id", cl.UserID).One(&m) + if e == orm.ErrNoRows { + passwordReply(&c.Controller, 404, "记录不存在", nil) + return + } + if e != nil { + logs.Error("[passwordStore] app detail failed: %v", e) + passwordReply(&c.Controller, 500, "查询失败: "+e.Error(), nil) + return + } + passwordReply(&c.Controller, 200, "success", PasswordStoreItemDTO{ + ID: m.ID, Tid: m.Tid, Platform: m.Platform, URL: m.URL, + Accounts: accountsFromJSON(m.Accounts), Remark: m.Remark, + UserID: m.UserID, CreateTime: m.CreateTime, UpdateTime: m.UpdateTime, + }) +} + +// Create POST /api/passwordStore/create +func (c *AppPasswordStoreController) Create() { + cl, e := c.appPwdClaims() + if e != nil { + passwordReply(&c.Controller, 401, "未登录或无权限", nil) + return + } + p, e := parsePassword(&c.Controller) + if e != nil { + passwordReply(&c.Controller, 400, e.Error(), nil) + return + } + if !validPassword(p) { + passwordReply(&c.Controller, 400, "请输入平台名称", nil) + return + } + if e := validateAccountsUnique(p.Accounts); e != nil { + passwordReply(&c.Controller, 400, e.Error(), nil) + return + } + qs := models.Orm.QueryTable(new(models.BackendPasswordStore)). + Filter("is_deleted", 0).Filter("tid", cl.TenantId).Filter("user_id", cl.UserID) + if existing, e := findSamePlatformRecord(qs, 0, p.Platform, p.URL); e != nil { + passwordReply(&c.Controller, 500, "查询失败: "+e.Error(), nil) + return + } else if existing > 0 { + passwordReply(&c.Controller, 400, "同平台同网址记录已存在,请勿重复添加", nil) + return + } + m := models.BackendPasswordStore{ + Tid: cl.TenantId, UserID: uint64(cl.UserID), + Platform: p.Platform, URL: p.URL, + Accounts: accountsToJSON(p.Accounts), Remark: p.Remark, + } + if _, e = models.Orm.Insert(&m); e != nil { + logs.Error("[passwordStore] app create failed: %v", e) + passwordReply(&c.Controller, 500, "创建失败: "+e.Error(), nil) + return + } + passwordReply(&c.Controller, 200, "success", PasswordStoreItemDTO{ + ID: m.ID, Tid: m.Tid, Platform: m.Platform, URL: m.URL, + Accounts: p.Accounts, Remark: m.Remark, + UserID: m.UserID, CreateTime: m.CreateTime, UpdateTime: m.UpdateTime, + }) +} + +// Update POST /api/passwordStore/update/:id +func (c *AppPasswordStoreController) Update() { + cl, e := c.appPwdClaims() + if e != nil { + passwordReply(&c.Controller, 401, "未登录或无权限", nil) + return + } + id, e := strconv.Atoi(c.Ctx.Input.Param(":id")) + if e != nil { + passwordReply(&c.Controller, 400, "参数错误", nil) + return + } + p, e := parsePassword(&c.Controller) + if e != nil { + passwordReply(&c.Controller, 400, e.Error(), nil) + return + } + if !validPassword(p) { + passwordReply(&c.Controller, 400, "请输入平台名称", nil) + return + } + if e := validateAccountsUnique(p.Accounts); e != nil { + passwordReply(&c.Controller, 400, e.Error(), nil) + return + } + var m models.BackendPasswordStore + e = models.Orm.QueryTable(new(models.BackendPasswordStore)). + Filter("id", id).Filter("is_deleted", 0).Filter("tid", cl.TenantId).Filter("user_id", cl.UserID).One(&m) + if e == orm.ErrNoRows { + passwordReply(&c.Controller, 404, "记录不存在", nil) + return + } + if e != nil { + logs.Error("[passwordStore] app update query failed: %v", e) + passwordReply(&c.Controller, 500, "查询失败: "+e.Error(), nil) + return + } + qs := models.Orm.QueryTable(new(models.BackendPasswordStore)). + Filter("is_deleted", 0).Filter("tid", cl.TenantId).Filter("user_id", cl.UserID) + if existing, e := findSamePlatformRecord(qs, m.ID, p.Platform, p.URL); e != nil { + passwordReply(&c.Controller, 500, "查询失败: "+e.Error(), nil) + return + } else if existing > 0 { + passwordReply(&c.Controller, 400, "同平台同网址记录已存在,请勿重复添加", nil) + return + } + m.Platform = p.Platform + m.URL = p.URL + m.Remark = p.Remark + m.Accounts = accountsToJSON(p.Accounts) + if _, e = models.Orm.Update(&m); e != nil { + logs.Error("[passwordStore] app update failed: %v", e) + passwordReply(&c.Controller, 500, "更新失败: "+e.Error(), nil) + return + } + passwordReply(&c.Controller, 200, "success", PasswordStoreItemDTO{ + ID: m.ID, Tid: m.Tid, Platform: m.Platform, URL: m.URL, + Accounts: p.Accounts, Remark: m.Remark, + UserID: m.UserID, CreateTime: m.CreateTime, UpdateTime: m.UpdateTime, + }) +} + +// Delete DELETE /api/passwordStore/delete/:id +func (c *AppPasswordStoreController) Delete() { + cl, e := c.appPwdClaims() + if e != nil { + passwordReply(&c.Controller, 401, "未登录或无权限", nil) + return + } + id, e := strconv.Atoi(c.Ctx.Input.Param(":id")) + if e != nil { + passwordReply(&c.Controller, 400, "参数错误", nil) + return + } + var m models.BackendPasswordStore + e = models.Orm.QueryTable(new(models.BackendPasswordStore)). + Filter("id", id).Filter("is_deleted", 0).Filter("tid", cl.TenantId).Filter("user_id", cl.UserID).One(&m) + if e == orm.ErrNoRows { + passwordReply(&c.Controller, 404, "记录不存在", nil) + return + } + if e != nil { + logs.Error("[passwordStore] app delete query failed: %v", e) + passwordReply(&c.Controller, 500, "查询失败: "+e.Error(), nil) + return + } + if _, e = models.Orm.Delete(&m); e != nil { + logs.Error("[passwordStore] app delete failed: %v", e) + passwordReply(&c.Controller, 500, "删除失败: "+e.Error(), nil) + return + } + middleware.WriteDeleteLog(uint64(cl.UserID), cl.TenantId, "passwordStore", m.Platform) + passwordReply(&c.Controller, 200, "success", nil) +} diff --git a/go/routers/api/api.go b/go/routers/api/api.go index 12a4bb1..b445197 100644 --- a/go/routers/api/api.go +++ b/go/routers/api/api.go @@ -75,6 +75,11 @@ func Register() { beego.Router("/api/schedule/:id", &controllers.AppReminderController{}, "get:GetDetail;put:Update;delete:Delete") beego.Router("/api/schedule/:id/toggle", &controllers.AppReminderController{}, "post:ToggleComplete") + // 账号管理(密码库,与 /backend/passwordStore/* 同一套数据;字面量路由在 :id 通配之前) + beego.Router("/api/passwordStore/list", &controllers.AppPasswordStoreController{}, "get:GetList") + beego.Router("/api/passwordStore", &controllers.AppPasswordStoreController{}, "post:Create") + beego.Router("/api/passwordStore/:id", &controllers.AppPasswordStoreController{}, "get:GetDetail;post:Update;delete:Delete") + // 记事本 beego.Router("/api/notebook/list", &controllers.AppNotebookController{}, "get:GetList") beego.Router("/api/notebook", &controllers.AppNotebookController{}, "post:Create") diff --git a/platform/src/views/login/index.vue b/platform/src/views/login/index.vue index ac48d67..6aa45b5 100644 --- a/platform/src/views/login/index.vue +++ b/platform/src/views/login/index.vue @@ -519,7 +519,6 @@ onMounted(() => { .catch(() => {}); }); -const goRegister = () => router.push("/register"); const goForget = () => router.push("/forget"); const clearCache = async () => { @@ -892,10 +891,6 @@ const clearCache = async () => { font-size: 13px; } -.register-link { - margin-right: 0px; -} - .forget-link { margin-left: 0px; } diff --git a/uniapp/api/passwordStore.js b/uniapp/api/passwordStore.js new file mode 100644 index 0000000..938e0fe --- /dev/null +++ b/uniapp/api/passwordStore.js @@ -0,0 +1,77 @@ +import { request } from '@/api/request.js' + +/** + * 账号管理(密码库)——记录个人各平台账号。 + * 与 Web 端密码存储管理同一套数据(一个平台下挂多个账号)。 + * 服务端自动过滤当前登录用户的记录,无需传 user_id。 + */ +export function fetchPasswordStores(keyword) { + return request({ + url: '/api/passwordStore/list', + data: keyword ? { keyword } : {} + }).then(data => ({ + list: (data.list || []).map(normalizeStore), + total: data.total || 0 + })) +} + +export function getPasswordStore(id) { + return request({ + url: `/api/passwordStore/detail/${id}` + }).then(normalizeStore) +} + +export function createPasswordStore(data) { + return request({ + url: '/api/passwordStore/create', + method: 'POST', + data: pickStore(data) + }).then(normalizeStore) +} + +export function updatePasswordStore(id, data) { + return request({ + url: `/api/passwordStore/update/${id}`, + method: 'POST', + data: pickStore(data) + }).then(normalizeStore) +} + +export function deletePasswordStore(id) { + return request({ + url: `/api/passwordStore/delete/${id}`, + method: 'DELETE' + }).then(() => true) +} + +/** 只取服务端接收的字段 */ +function pickStore(data) { + return { + platform: data.platform || '', + url: data.url || '', + remark: data.remark || '', + accounts: (data.accounts || []).map(a => ({ + username: a.username || '', + password: a.password || '', + registration_info: a.registration_info || '', + remark: a.remark || '' + })) + } +} + +/** 统一账号列表结构,避免后端缺字段导致渲染报错 */ +function normalizeStore(item) { + const store = item || {} + return { + ...store, + platform: store.platform || '', + url: store.url || '', + remark: store.remark || '', + accounts: (store.accounts || []).map(a => ({ + username: a.username || '', + password: a.password || '', + registration_info: a.registration_info || '', + remark: a.remark || '' + })) + } +} diff --git a/uniapp/components/NoteRichEditor.vue b/uniapp/components/NoteRichEditor.vue index e57bf0a..c36e2d8 100644 --- a/uniapp/components/NoteRichEditor.vue +++ b/uniapp/components/NoteRichEditor.vue @@ -608,52 +608,32 @@ export default { diff --git a/uniapp/pages.json b/uniapp/pages.json index aff884f..f82c6c3 100644 --- a/uniapp/pages.json +++ b/uniapp/pages.json @@ -22,381 +22,6 @@ "navigationBarTitleText": "子系统" } }, - { - "path": "pages/crm/home/home", - "style": { - "navigationStyle": "custom", - "navigationBarTitleText": "客户关系管理" - } - }, - { - "path": "pages/crm/functions/functions", - "style": { - "navigationStyle": "custom", - "navigationBarTitleText": "客户关系 · 功能" - } - }, - { - "path": "pages/crm/todo/todo", - "style": { - "navigationStyle": "custom", - "navigationBarTitleText": "客户关系 · 待办" - } - }, - { - "path": "pages/crm/mine/mine", - "style": { - "navigationStyle": "custom", - "navigationBarTitleText": "客户关系 · 我的" - } - }, - { - "path": "pages/erp/home/home", - "style": { - "navigationStyle": "custom", - "navigationBarTitleText": "进销存管理" - } - }, - { - "path": "pages/erp/functions/functions", - "style": { - "navigationStyle": "custom", - "navigationBarTitleText": "进销存 · 功能" - } - }, - { - "path": "pages/erp/todo/todo", - "style": { - "navigationStyle": "custom", - "navigationBarTitleText": "进销存 · 待办" - } - }, - { - "path": "pages/erp/mine/mine", - "style": { - "navigationStyle": "custom", - "navigationBarTitleText": "进销存 · 我的" - } - }, - { - "path": "pages/erp/dashboard/index", - "style": { - "navigationBarTitleText": "进销存工作台", - "navigationBarBackgroundColor": "#F8FAFC", - "navigationBarTextStyle": "black" - } - }, - { - "path": "pages/erp/document/index", - "style": { - "navigationBarTitleText": "单据列表", - "navigationBarBackgroundColor": "#F8FAFC", - "navigationBarTextStyle": "black" - } - }, - { - "path": "pages/erp/document/detail", - "style": { - "navigationBarTitleText": "单据详情", - "navigationBarBackgroundColor": "#F8FAFC", - "navigationBarTextStyle": "black" - } - }, - { - "path": "pages/erp/document/edit", - "style": { - "navigationBarTitleText": "开单", - "navigationBarBackgroundColor": "#F8FAFC", - "navigationBarTextStyle": "black" - } - }, - { - "path": "pages/erp/basic/product", - "style": { - "navigationBarTitleText": "商品档案", - "navigationBarBackgroundColor": "#F8FAFC", - "navigationBarTextStyle": "black" - } - }, - { - "path": "pages/erp/basic/product-detail", - "style": { - "navigationBarTitleText": "商品详情", - "navigationBarBackgroundColor": "#F8FAFC", - "navigationBarTextStyle": "black" - } - }, - { - "path": "pages/erp/basic/warehouse", - "style": { - "navigationBarTitleText": "仓库档案", - "navigationBarBackgroundColor": "#F8FAFC", - "navigationBarTextStyle": "black" - } - }, - { - "path": "pages/erp/partner/index", - "style": { - "navigationBarTitleText": "客商管理", - "navigationBarBackgroundColor": "#F8FAFC", - "navigationBarTextStyle": "black" - } - }, - { - "path": "pages/erp/partner/detail", - "style": { - "navigationBarTitleText": "客商详情", - "navigationBarBackgroundColor": "#F8FAFC", - "navigationBarTextStyle": "black" - } - }, - { - "path": "pages/erp/stock/index", - "style": { - "navigationBarTitleText": "库存结存", - "navigationBarBackgroundColor": "#F8FAFC", - "navigationBarTextStyle": "black" - } - }, - { - "path": "pages/erp/stock/ledger", - "style": { - "navigationBarTitleText": "收发存流水", - "navigationBarBackgroundColor": "#F8FAFC", - "navigationBarTextStyle": "black" - } - }, - { - "path": "pages/erp/stock/batch", - "style": { - "navigationBarTitleText": "批次效期", - "navigationBarBackgroundColor": "#F8FAFC", - "navigationBarTextStyle": "black" - } - }, - { - "path": "pages/erp/stock/warning", - "style": { - "navigationBarTitleText": "库存预警", - "navigationBarBackgroundColor": "#F8FAFC", - "navigationBarTextStyle": "black" - } - }, - { - "path": "pages/erp/finance/bill", - "style": { - "navigationBarTitleText": "应收应付", - "navigationBarBackgroundColor": "#F8FAFC", - "navigationBarTextStyle": "black" - } - }, - { - "path": "pages/erp/finance/bill-detail", - "style": { - "navigationBarTitleText": "账单详情", - "navigationBarBackgroundColor": "#F8FAFC", - "navigationBarTextStyle": "black" - } - }, - { - "path": "pages/erp/finance/fund", - "style": { - "navigationBarTitleText": "收付款单", - "navigationBarBackgroundColor": "#F8FAFC", - "navigationBarTextStyle": "black" - } - }, - { - "path": "pages/erp/finance/fund-edit", - "style": { - "navigationBarTitleText": "收付款", - "navigationBarBackgroundColor": "#F8FAFC", - "navigationBarTextStyle": "black" - } - }, - { - "path": "pages/erp/report/index", - "style": { - "navigationBarTitleText": "报表中心", - "navigationBarBackgroundColor": "#F8FAFC", - "navigationBarTextStyle": "black" - } - }, - { - "path": "pages/oa/home/home", - "style": { - "navigationStyle": "custom", - "navigationBarTitleText": "协同办公" - } - }, - { - "path": "pages/oa/functions/functions", - "style": { - "navigationStyle": "custom", - "navigationBarTitleText": "OA · 功能" - } - }, - { - "path": "pages/oa/todo/todo", - "style": { - "navigationStyle": "custom", - "navigationBarTitleText": "OA · 待办" - } - }, - { - "path": "pages/oa/mine/mine", - "style": { - "navigationStyle": "custom", - "navigationBarTitleText": "OA · 我的" - } - }, - { - "path": "pages/oa/notice/index", - "style": { - "navigationBarTitleText": "通知公告", - "navigationBarBackgroundColor": "#F8FAFC" - } - }, - { - "path": "pages/oa/dailyreport/index", - "style": { - "navigationBarTitleText": "工作日报", - "navigationBarBackgroundColor": "#F8FAFC" - } - }, - { - "path": "pages/oa/dailyreport/edit", - "style": { - "navigationBarTitleText": "填写日报", - "navigationBarBackgroundColor": "#F8FAFC" - } - }, - { - "path": "pages/oa/dailyreport/detail", - "style": { - "navigationBarTitleText": "日报详情", - "navigationBarBackgroundColor": "#F8FAFC" - } - }, - { - "path": "pages/oa/notice/detail", - "style": { - "navigationBarTitleText": "公告详情", - "navigationBarBackgroundColor": "#F8FAFC" - } - }, - { - "path": "pages/oa/document/index", - "style": { - "navigationBarTitleText": "文档库", - "navigationBarBackgroundColor": "#F8FAFC" - } - }, - { - "path": "pages/oa/document/detail", - "style": { - "navigationBarTitleText": "文档详情", - "navigationBarBackgroundColor": "#F8FAFC" - } - }, - { - "path": "pages/oa/compensation/index", - "style": { - "navigationBarTitleText": "我的工资单", - "navigationBarBackgroundColor": "#F8FAFC" - } - }, - { - "path": "pages/oa/compensation/detail", - "style": { - "navigationBarTitleText": "工资单明细", - "navigationBarBackgroundColor": "#F8FAFC" - } - }, - { - "path": "pages/oa/employeefile/index", - "style": { - "navigationBarTitleText": "员工档案", - "navigationBarBackgroundColor": "#F8FAFC" - } - }, - { - "path": "pages/oa/employeefile/detail", - "style": { - "navigationBarTitleText": "档案详情", - "navigationBarBackgroundColor": "#F8FAFC" - } - }, - { - "path": "pages/oa/contact/index", - "style": { - "navigationBarTitleText": "通讯录", - "navigationBarBackgroundColor": "#F8FAFC" - } - }, - { - "path": "pages/oa/contact/detail", - "style": { - "navigationBarTitleText": "联系人详情", - "navigationBarBackgroundColor": "#F8FAFC" - } - }, - { - "path": "pages/cms/home/home", - "style": { - "navigationStyle": "custom", - "navigationBarTitleText": "网站内容管理" - } - }, - { - "path": "pages/cms/functions/functions", - "style": { - "navigationStyle": "custom", - "navigationBarTitleText": "网站管理 · 功能" - } - }, - { - "path": "pages/cms/todo/todo", - "style": { - "navigationStyle": "custom", - "navigationBarTitleText": "网站管理 · 待办" - } - }, - { - "path": "pages/cms/mine/mine", - "style": { - "navigationStyle": "custom", - "navigationBarTitleText": "网站管理 · 我的" - } - }, - { - "path": "pages/toolbox/home/home", - "style": { - "navigationStyle": "custom", - "navigationBarTitleText": "便捷工具" - } - }, - { - "path": "pages/toolbox/functions/functions", - "style": { - "navigationStyle": "custom", - "navigationBarTitleText": "便捷工具 · 功能" - } - }, - { - "path": "pages/toolbox/todo/todo", - "style": { - "navigationStyle": "custom", - "navigationBarTitleText": "便捷工具 · 待办" - } - }, - { - "path": "pages/toolbox/mine/mine", - "style": { - "navigationStyle": "custom", - "navigationBarTitleText": "便捷工具 · 我的" - } - }, { "path": "pages/login/login", "style": { @@ -475,90 +100,523 @@ "navigationStyle": "custom", "navigationBarTitleText": "我的" } + } + ], + "subPackages": [ + { + "root": "pages/crm", + "pages": [ + { + "path": "home/home", + "style": { + "navigationStyle": "custom", + "navigationBarTitleText": "客户关系管理" + } + }, + { + "path": "functions/functions", + "style": { + "navigationStyle": "custom", + "navigationBarTitleText": "客户关系 · 功能" + } + }, + { + "path": "todo/todo", + "style": { + "navigationStyle": "custom", + "navigationBarTitleText": "客户关系 · 待办" + } + }, + { + "path": "mine/mine", + "style": { + "navigationStyle": "custom", + "navigationBarTitleText": "客户关系 · 我的" + } + } + ] }, { - "path": "pages/tools/notepad/index", - "style": { - "navigationBarTitleText": "记事本", - "navigationBarBackgroundColor": "#F8FAFC" - } + "root": "pages/erp", + "pages": [ + { + "path": "home/home", + "style": { + "navigationStyle": "custom", + "navigationBarTitleText": "进销存管理" + } + }, + { + "path": "functions/functions", + "style": { + "navigationStyle": "custom", + "navigationBarTitleText": "进销存 · 功能" + } + }, + { + "path": "todo/todo", + "style": { + "navigationStyle": "custom", + "navigationBarTitleText": "进销存 · 待办" + } + }, + { + "path": "mine/mine", + "style": { + "navigationStyle": "custom", + "navigationBarTitleText": "进销存 · 我的" + } + }, + { + "path": "dashboard/index", + "style": { + "navigationBarTitleText": "进销存工作台", + "navigationBarBackgroundColor": "#F8FAFC", + "navigationBarTextStyle": "black" + } + }, + { + "path": "document/index", + "style": { + "navigationBarTitleText": "单据列表", + "navigationBarBackgroundColor": "#F8FAFC", + "navigationBarTextStyle": "black" + } + }, + { + "path": "document/detail", + "style": { + "navigationBarTitleText": "单据详情", + "navigationBarBackgroundColor": "#F8FAFC", + "navigationBarTextStyle": "black" + } + }, + { + "path": "document/edit", + "style": { + "navigationBarTitleText": "开单", + "navigationBarBackgroundColor": "#F8FAFC", + "navigationBarTextStyle": "black" + } + }, + { + "path": "basic/product", + "style": { + "navigationBarTitleText": "商品档案", + "navigationBarBackgroundColor": "#F8FAFC", + "navigationBarTextStyle": "black" + } + }, + { + "path": "basic/product-detail", + "style": { + "navigationBarTitleText": "商品详情", + "navigationBarBackgroundColor": "#F8FAFC", + "navigationBarTextStyle": "black" + } + }, + { + "path": "basic/warehouse", + "style": { + "navigationBarTitleText": "仓库档案", + "navigationBarBackgroundColor": "#F8FAFC", + "navigationBarTextStyle": "black" + } + }, + { + "path": "partner/index", + "style": { + "navigationBarTitleText": "客商管理", + "navigationBarBackgroundColor": "#F8FAFC", + "navigationBarTextStyle": "black" + } + }, + { + "path": "partner/detail", + "style": { + "navigationBarTitleText": "客商详情", + "navigationBarBackgroundColor": "#F8FAFC", + "navigationBarTextStyle": "black" + } + }, + { + "path": "stock/index", + "style": { + "navigationBarTitleText": "库存结存", + "navigationBarBackgroundColor": "#F8FAFC", + "navigationBarTextStyle": "black" + } + }, + { + "path": "stock/ledger", + "style": { + "navigationBarTitleText": "收发存流水", + "navigationBarBackgroundColor": "#F8FAFC", + "navigationBarTextStyle": "black" + } + }, + { + "path": "stock/batch", + "style": { + "navigationBarTitleText": "批次效期", + "navigationBarBackgroundColor": "#F8FAFC", + "navigationBarTextStyle": "black" + } + }, + { + "path": "stock/warning", + "style": { + "navigationBarTitleText": "库存预警", + "navigationBarBackgroundColor": "#F8FAFC", + "navigationBarTextStyle": "black" + } + }, + { + "path": "finance/bill", + "style": { + "navigationBarTitleText": "应收应付", + "navigationBarBackgroundColor": "#F8FAFC", + "navigationBarTextStyle": "black" + } + }, + { + "path": "finance/bill-detail", + "style": { + "navigationBarTitleText": "账单详情", + "navigationBarBackgroundColor": "#F8FAFC", + "navigationBarTextStyle": "black" + } + }, + { + "path": "finance/fund", + "style": { + "navigationBarTitleText": "收付款单", + "navigationBarBackgroundColor": "#F8FAFC", + "navigationBarTextStyle": "black" + } + }, + { + "path": "finance/fund-edit", + "style": { + "navigationBarTitleText": "收付款", + "navigationBarBackgroundColor": "#F8FAFC", + "navigationBarTextStyle": "black" + } + }, + { + "path": "report/index", + "style": { + "navigationBarTitleText": "报表中心", + "navigationBarBackgroundColor": "#F8FAFC", + "navigationBarTextStyle": "black" + } + } + ] }, { - "path": "pages/tools/notepad/edit", - "style": { - "navigationBarTitleText": "新建笔记", - "navigationBarBackgroundColor": "#F8FAFC" - } + "root": "pages/oa", + "pages": [ + { + "path": "home/home", + "style": { + "navigationStyle": "custom", + "navigationBarTitleText": "协同办公" + } + }, + { + "path": "functions/functions", + "style": { + "navigationStyle": "custom", + "navigationBarTitleText": "OA · 功能" + } + }, + { + "path": "todo/todo", + "style": { + "navigationStyle": "custom", + "navigationBarTitleText": "OA · 待办" + } + }, + { + "path": "mine/mine", + "style": { + "navigationStyle": "custom", + "navigationBarTitleText": "OA · 我的" + } + }, + { + "path": "notice/index", + "style": { + "navigationBarTitleText": "通知公告", + "navigationBarBackgroundColor": "#F8FAFC" + } + }, + { + "path": "dailyreport/index", + "style": { + "navigationBarTitleText": "工作日报", + "navigationBarBackgroundColor": "#F8FAFC" + } + }, + { + "path": "dailyreport/edit", + "style": { + "navigationBarTitleText": "填写日报", + "navigationBarBackgroundColor": "#F8FAFC" + } + }, + { + "path": "dailyreport/detail", + "style": { + "navigationBarTitleText": "日报详情", + "navigationBarBackgroundColor": "#F8FAFC" + } + }, + { + "path": "notice/detail", + "style": { + "navigationBarTitleText": "公告详情", + "navigationBarBackgroundColor": "#F8FAFC" + } + }, + { + "path": "document/index", + "style": { + "navigationBarTitleText": "文档库", + "navigationBarBackgroundColor": "#F8FAFC" + } + }, + { + "path": "document/detail", + "style": { + "navigationBarTitleText": "文档详情", + "navigationBarBackgroundColor": "#F8FAFC" + } + }, + { + "path": "compensation/index", + "style": { + "navigationBarTitleText": "我的工资单", + "navigationBarBackgroundColor": "#F8FAFC" + } + }, + { + "path": "compensation/detail", + "style": { + "navigationBarTitleText": "工资单明细", + "navigationBarBackgroundColor": "#F8FAFC" + } + }, + { + "path": "employeefile/index", + "style": { + "navigationBarTitleText": "员工档案", + "navigationBarBackgroundColor": "#F8FAFC" + } + }, + { + "path": "employeefile/detail", + "style": { + "navigationBarTitleText": "档案详情", + "navigationBarBackgroundColor": "#F8FAFC" + } + }, + { + "path": "contact/index", + "style": { + "navigationBarTitleText": "通讯录", + "navigationBarBackgroundColor": "#F8FAFC" + } + }, + { + "path": "contact/detail", + "style": { + "navigationBarTitleText": "联系人详情", + "navigationBarBackgroundColor": "#F8FAFC" + } + } + ] }, { - "path": "pages/tools/schedule/index", - "style": { - "navigationBarTitleText": "工作日程", - "navigationBarBackgroundColor": "#F8FAFC" - } + "root": "pages/cms", + "pages": [ + { + "path": "home/home", + "style": { + "navigationStyle": "custom", + "navigationBarTitleText": "网站内容管理" + } + }, + { + "path": "functions/functions", + "style": { + "navigationStyle": "custom", + "navigationBarTitleText": "网站管理 · 功能" + } + }, + { + "path": "todo/todo", + "style": { + "navigationStyle": "custom", + "navigationBarTitleText": "网站管理 · 待办" + } + }, + { + "path": "mine/mine", + "style": { + "navigationStyle": "custom", + "navigationBarTitleText": "网站管理 · 我的" + } + } + ] }, { - "path": "pages/tools/schedule/reminder", - "style": { - "navigationBarTitleText": "日程提醒", - "navigationBarBackgroundColor": "#F8FAFC" - } + "root": "pages/toolbox", + "pages": [ + { + "path": "home/home", + "style": { + "navigationStyle": "custom", + "navigationBarTitleText": "便捷工具" + } + }, + { + "path": "functions/functions", + "style": { + "navigationStyle": "custom", + "navigationBarTitleText": "便捷工具 · 功能" + } + }, + { + "path": "todo/todo", + "style": { + "navigationStyle": "custom", + "navigationBarTitleText": "便捷工具 · 待办" + } + }, + { + "path": "mine/mine", + "style": { + "navigationStyle": "custom", + "navigationBarTitleText": "便捷工具 · 我的" + } + } + ] }, { - "path": "pages/tools/schedule/detail", - "style": { - "navigationBarTitleText": "日程详情", - "navigationBarBackgroundColor": "#F8FAFC" - } + "root": "pages/tools", + "pages": [ + { + "path": "notepad/index", + "style": { + "navigationBarTitleText": "记事本", + "navigationBarBackgroundColor": "#F8FAFC" + } + }, + { + "path": "notepad/edit", + "style": { + "navigationBarTitleText": "新建笔记", + "navigationBarBackgroundColor": "#F8FAFC" + } + }, + { + "path": "schedule/index", + "style": { + "navigationBarTitleText": "工作日程", + "navigationBarBackgroundColor": "#F8FAFC" + } + }, + { + "path": "schedule/reminder", + "style": { + "navigationBarTitleText": "日程提醒", + "navigationBarBackgroundColor": "#F8FAFC" + } + }, + { + "path": "schedule/reminder-edit", + "style": { + "navigationBarTitleText": "新增日程提醒", + "navigationBarBackgroundColor": "#F8FAFC" + } + }, + { + "path": "schedule/detail", + "style": { + "navigationBarTitleText": "日程详情", + "navigationBarBackgroundColor": "#F8FAFC" + } + }, + { + "path": "schedule/edit", + "style": { + "navigationBarTitleText": "新建日程", + "navigationBarBackgroundColor": "#F8FAFC" + } + }, + { + "path": "expense/index", + "style": { + "navigationBarTitleText": "报销管理", + "navigationBarBackgroundColor": "#F8FAFC" + } + }, + { + "path": "expense/edit", + "style": { + "navigationBarTitleText": "新建报销单", + "navigationBarBackgroundColor": "#F8FAFC" + } + }, + { + "path": "account/index", + "style": { + "navigationBarTitleText": "账号管理", + "navigationBarBackgroundColor": "#F8FAFC" + } + }, + { + "path": "account/edit", + "style": { + "navigationBarTitleText": "新增账号", + "navigationBarBackgroundColor": "#F8FAFC" + } + }, + { + "path": "expense/detail", + "style": { + "navigationBarTitleText": "报销详情", + "navigationBarBackgroundColor": "#F8FAFC" + } + } + ] }, { - "path": "pages/tools/schedule/edit", - "style": { - "navigationBarTitleText": "新建日程", - "navigationBarBackgroundColor": "#F8FAFC" - } - }, - { - "path": "pages/tools/expense/index", - "style": { - "navigationBarTitleText": "报销管理", - "navigationBarBackgroundColor": "#F8FAFC" - } - }, - { - "path": "pages/tools/expense/edit", - "style": { - "navigationBarTitleText": "新建报销单", - "navigationBarBackgroundColor": "#F8FAFC" - } - }, - { - "path": "pages/tools/expense/detail", - "style": { - "navigationBarTitleText": "报销详情", - "navigationBarBackgroundColor": "#F8FAFC" - } - }, - { - "path": "pages/approval/index", - "style": { - "navigationBarTitleText": "审批列表", - "navigationBarBackgroundColor": "#F8FAFC" - } - }, - { - "path": "pages/approval/detail", - "style": { - "navigationBarTitleText": "审批详情", - "navigationBarBackgroundColor": "#F8FAFC" - } - }, - { - "path": "pages/approval/verify", - "style": { - "navigationBarTitleText": "待我审批", - "navigationBarBackgroundColor": "#F8FAFC" - } + "root": "pages/approval", + "pages": [ + { + "path": "index", + "style": { + "navigationBarTitleText": "审批列表", + "navigationBarBackgroundColor": "#F8FAFC" + } + }, + { + "path": "detail", + "style": { + "navigationBarTitleText": "审批详情", + "navigationBarBackgroundColor": "#F8FAFC" + } + }, + { + "path": "verify", + "style": { + "navigationBarTitleText": "待我审批", + "navigationBarBackgroundColor": "#F8FAFC" + } + } + ] } ], "globalStyle": { diff --git a/uniapp/pages/login/login.vue b/uniapp/pages/login/login.vue index a343c0e..2067f20 100644 --- a/uniapp/pages/login/login.vue +++ b/uniapp/pages/login/login.vue @@ -1,176 +1,195 @@ @@ -203,9 +222,25 @@ import { import { showGeetest4 } from '@/utils/geetest.js' import FaIcon from '@/components/FaIcon.vue' -const step = ref('password') -/** 小程序端登录方式 Tab:wechat / account(其他端固定账号密码) */ -const activeTab = ref('wechat') +/** 运行端检测:h5 / apk(app-plus) / mp-weixin,决定登录方式优先级 */ +const platform = ref('') +// #ifdef H5 +platform.value = 'h5' +// #endif +// #ifdef APP-PLUS +platform.value = 'apk' +// #endif +// #ifdef MP-WEIXIN +platform.value = 'mp-weixin' +// #endif + +/** + * 视图状态: + * main 微信一键登录主入口(小程序端默认视图) + * account 账号密码登录(独立视图,由主视图弱化入口进入) + * tenant 选择企业(一人多企业) + */ +const step = ref(platform.value === 'mp-weixin' ? 'main' : 'account') const account = ref('') const password = ref('') const showPassword = ref(false) @@ -221,33 +256,65 @@ const verifyCfg = ref({ needGeetest: false, captchaId: '' }) /** 仅微信小程序端且服务端已开通时展示「一键登录」入口 */ const showMiniLogin = ref(false) -/** 面板副标题:随 Tab 切换提示文案 */ -const panelSub = computed(() => { - if (platform.value === 'mp-weixin' && showMiniLogin.value && activeTab.value === 'wechat') { - return '使用微信一键登录,或切换到账号密码登录' - } - return '请输入您的账号与密码以继续' +/** 顶部导航标题 */ +const navTitle = computed(() => { + if (step.value === 'tenant') return '选择企业' + return '账号密码登录' }) -/** 切换登录方式 Tab:清掉上一次残留的错误提示 */ -function switchTab(tab) { +/** + * 状态栏高度(px)。 + * 小程序端 env(safe-area-inset-top) 在无刘海的安卓机型返回 0, + * 自绘导航会被状态栏压住,因此这里取系统信息里的真实状态栏高度。 + */ +const statusBarHeight = ref(0) +try { + const info = + typeof uni.getWindowInfo === 'function' ? uni.getWindowInfo() : uni.getSystemInfoSync() + statusBarHeight.value = (info && info.statusBarHeight) || 0 +} catch (e) { + statusBarHeight.value = 0 +} + +/** 自绘导航的上内边距:状态栏高度(导航本体固定 88rpx) */ +const navPadTop = computed(() => `${statusBarHeight.value}px`) + +/** 品牌区上内边距:主视图需让开状态栏,紧凑视图(账号/企业)由导航栏已占位 */ +const brandPadTop = computed(() => { + if (step.value !== 'main') return '32rpx' + return `${statusBarHeight.value + uni.upx2px(88)}px` +}) + +/** 是否存在可返回的上级视图(账号密码视图仅在小程序端可退回主视图) */ +const canGoBack = computed(() => { + if (step.value === 'tenant') return true + if (step.value === 'account') return showMiniLogin.value + return false +}) + +/** 切换到账号密码登录视图 */ +function goAccount() { if (submitting.value) return - if (activeTab.value === tab) return - activeTab.value = tab + step.value = 'account' errorMsg.value = '' } -/** 运行端检测:h5 / apk(app-plus) / mp-weixin,决定登录方式优先级 */ -const platform = ref('') -// #ifdef H5 -platform.value = 'h5' -// #endif -// #ifdef APP-PLUS -platform.value = 'apk' -// #endif -// #ifdef MP-WEIXIN -platform.value = 'mp-weixin' -// #endif +/** 返回微信一键登录主视图 */ +function goMain() { + if (submitting.value) return + if (!showMiniLogin.value) return + step.value = 'main' + errorMsg.value = '' +} + +/** 顶部导航返回 */ +function onNavBack() { + if (step.value === 'tenant') { + backToAccount() + return + } + goMain() +} onMounted(async () => { if (isLoggedIn()) { @@ -259,8 +326,6 @@ onMounted(async () => { if (remembered.rememberMe) { rememberMe.value = true account.value = remembered.account - // 记住了账号,默认落在账号密码 Tab 更顺手 - activeTab.value = 'account' } loadVerifyConfig() @@ -289,6 +354,10 @@ async function loadMiniLoginConfig() { } catch { showMiniLogin.value = false } + // 服务端未开通一键登录:直接落到账号密码视图 + if (!showMiniLogin.value && step.value === 'main') { + step.value = 'account' + } } /* ==================== 登录主流程 ==================== */ @@ -394,9 +463,10 @@ function chooseTenant(item) { }) } +/** 从「选择企业」退回账号密码视图 */ function backToAccount() { clearAuthState() - step.value = 'password' + step.value = 'account' errorMsg.value = '' } @@ -524,13 +594,14 @@ function handleMiniError(err) { confirmText: '去登录', confirmColor: '#2563eb', success: (res) => { - if (res.confirm) switchTab('account') + if (res.confirm) goAccount() } }) return } if (reason === 'not_configured') { showMiniLogin.value = false + step.value = 'account' } showError(err) } @@ -553,11 +624,14 @@ function clearAuthState() { } function showError(err) { - errorMsg.value = (err && err.message) || '登录失败,请稍后重试' -} - -function goRegister() { - uni.navigateTo({ url: '/pages/login/register' }) + const raw = (err && err.message) || '' + // 微信未配置 request 合法域名:原始报错是英文,给出可操作的中文提示 + if (/url not in domain list/i.test(raw)) { + errorMsg.value = + '当前小程序未配置服务器域名,请在微信公众平台「开发管理 - 开发设置 - 服务器域名」中添加 api.yunzer.cn 为 request 合法域名' + return + } + errorMsg.value = raw || '登录失败,请稍后重试' } /** 勾选/取消用户协议:勾选后自动收起未勾选提示 */ @@ -621,53 +695,151 @@ function goForget() { + \ No newline at end of file diff --git a/uniapp/pages/nav/nav.vue b/uniapp/pages/nav/nav.vue index b450809..6586286 100644 --- a/uniapp/pages/nav/nav.vue +++ b/uniapp/pages/nav/nav.vue @@ -3,10 +3,18 @@ - 选择子系统 - {{ enabledCount }}/{{ cards.length }} 已开通 + + YUNZE WORKSPACE + 工作台 + + - {{ user.tenant || '云泽平台' }} · {{ user.account }} + + + 当前租户{{ user.tenant || '云泽平台' }} + 切换 + + 选择一个业务系统,开始高效工作 @@ -53,7 +61,8 @@ import { mpHeadPad } from '@/utils/mpHead.js' const headPad = mpHeadPad() import { onShow } from '@dcloudio/uni-app' -import { isLoggedIn } from '@/utils/auth.js' +import { isLoggedIn, getTenants, getTid, setAuthTokens, setTid, setTenantName, getUser, setUser } from '@/utils/auth.js' +import { switchTenant } from '@/api/auth.js' import { fetchHome } from '@/api/workspace.js' import { openMenu } from '@/utils/nav.js' import { getSubsystemByModule, goSubsystem } from '@/config/subsystems.js' @@ -80,6 +89,8 @@ const loadError = ref('') const user = ref({}) const modules = ref([]) const menus = ref([]) +const tenants = ref(getTenants()) +const switchingTenant = ref(false) /** 叶子菜单(可直接跳转的功能页),已锁定的过滤掉 */ const leafMenus = computed(() => menus.value.filter((m) => m.leaf !== false && !m.locked)) @@ -116,7 +127,6 @@ const cards = computed(() => { }) }) -const enabledCount = computed(() => cards.value.filter((c) => !c.locked).length) /* ==================== 数据加载 ==================== */ @@ -138,6 +148,41 @@ async function load(force = false) { /* ==================== 交互 ==================== */ +function chooseTenant() { + const list = tenants.value + if (list.length <= 1) { uni.showToast({ title: list.length ? '当前账号仅绑定一个租户' : '暂无可切换的租户', icon: 'none' }) + return + } + if (switchingTenant.value) return + uni.showActionSheet({ + itemList: list.map((tenant) => tenant.tenant_name || `企业${tenant.tid}`), + success: async ({ tapIndex }) => { + const tenant = list[tapIndex] + if (!tenant || String(tenant.tid) === String(getTid())) return + switchingTenant.value = true + uni.showLoading({ title: '正在切换...', mask: true }) + try { + const res = await switchTenant({ tid: tenant.tid }) + if (!res || !res.tokens) throw new Error((res && res.msg) || '切换租户失败') + setAuthTokens(res.tokens) + setTid(tenant.tid) + setTenantName(tenant.tenant_name || '') + const profile = getUser() || {} + const nextUser = { ...profile, tid: tenant.tid, tenant_name: tenant.tenant_name || '' } + setUser(nextUser) + user.value = { ...user.value, tenant: tenant.tenant_name || '', account: nextUser.account || user.value.account } + await load(true) + uni.showToast({ title: '已切换租户', icon: 'success' }) + } catch (e) { + uni.showToast({ title: (e && e.message) || '切换失败,请重试', icon: 'none' }) + } finally { + uni.hideLoading() + switchingTenant.value = false + } + } + }) +} + /** * 点击子系统卡片 → 进入该子系统独立页面组(带自己的 tabbar)。 * 未在 config/subsystems.js 注册的模块,降级为直接打开 Web 端该模块首页。 @@ -189,42 +234,80 @@ onShow(() => { /* ============ 顶部信息(融入页面背景) ============ */ .head { flex-shrink: 0; - padding: calc(var(--status-bar-height, 44px) + 32rpx) $page-padding-x 12rpx; + padding: calc(var(--status-bar-height, 44px) + 32rpx) $page-padding-x 28rpx; /* #ifdef MP-WEIXIN */ - /* 小程序端 --status-bar-height 固定 25px,需真实状态栏(env)+胶囊避让 */ padding-top: calc(env(safe-area-inset-top, 25px) + 96rpx); /* #endif */ - background: $color-bg-page; + background: linear-gradient(145deg, #eaf3ff 0%, #f5f9ff 58%, #ffffff 100%); + border-bottom: 1rpx solid #e5efff; } .head-row { display: flex; - align-items: baseline; + align-items: center; justify-content: space-between; gap: 16rpx; } +.head-eyebrow { + display: block; + margin-bottom: 8rpx; + font-size: 18rpx; + font-weight: 700; + letter-spacing: 3rpx; + color: #6e9de5; +} + .head-title { - font-size: 42rpx; - font-weight: 600; - color: $color-text; + display: block; + font-size: 44rpx; + font-weight: 700; + color: #17345f; letter-spacing: 1rpx; } -.head-count { - font-size: 23rpx; - color: $color-text-muted; - flex-shrink: 0; +.account-chip { + display: flex; + align-items: center; + gap: 9rpx; + padding: 12rpx 17rpx; + border-radius: 30rpx; + background: rgba(255,255,255,.85); + color: #526b8d; + font-size: 22rpx; } +.tenant-switch { + display: flex; + align-items: center; + margin-top: 28rpx; + padding: 20rpx 22rpx; + border: 1rpx solid #dceaff; + border-radius: 18rpx; + background: #ffffff; + box-shadow: 0 8rpx 24rpx rgba(47, 110, 196, .08); +} + +.tenant-mark { + width: 64rpx; + height: 64rpx; + border-radius: 16rpx; + display: flex; + align-items: center; + justify-content: center; + background: linear-gradient(145deg, #69a5ff, #3478f6); +} + +.tenant-copy { flex: 1; min-width: 0; margin-left: 16rpx; } +.tenant-label { display: block; font-size: 20rpx; color: #8a9bb3; } +.tenant-name { display: block; margin-top: 5rpx; font-size: 27rpx; font-weight: 600; color: #203b62; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.tenant-action { display: flex; align-items: center; gap: 8rpx; color: #3478f6; font-size: 22rpx; font-weight: 600; } + .head-sub { display: block; - margin-top: 8rpx; + margin-top: 22rpx; font-size: 23rpx; - color: $color-text-muted; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; + color: #8295b0; } /* ============ 内容区 ============ */ @@ -233,7 +316,8 @@ onShow(() => { min-height: 0; overflow-y: auto; -webkit-overflow-scrolling: touch; - padding: 8rpx $page-padding-x 0; + padding: 20rpx $page-padding-x 0; + background: #f5f8fd; } /* ============ 失败提示 ============ */ @@ -300,7 +384,9 @@ onShow(() => { .portal-card { @include card; - padding: 40rpx 16rpx 34rpx; + padding: 34rpx 16rpx 30rpx; + border: 1rpx solid #e6eef9; + box-shadow: 0 6rpx 20rpx rgba(38, 86, 150, .045); display: flex; flex-direction: column; align-items: center; diff --git a/uniapp/pages/tools/account/edit.vue b/uniapp/pages/tools/account/edit.vue new file mode 100644 index 0000000..a626919 --- /dev/null +++ b/uniapp/pages/tools/account/edit.vue @@ -0,0 +1,399 @@ + + + + + diff --git a/uniapp/pages/tools/account/index.vue b/uniapp/pages/tools/account/index.vue new file mode 100644 index 0000000..2e2ffa9 --- /dev/null +++ b/uniapp/pages/tools/account/index.vue @@ -0,0 +1,388 @@ + + + + + diff --git a/uniapp/pages/tools/schedule/reminder-edit.vue b/uniapp/pages/tools/schedule/reminder-edit.vue new file mode 100644 index 0000000..32ea386 --- /dev/null +++ b/uniapp/pages/tools/schedule/reminder-edit.vue @@ -0,0 +1,377 @@ + + + + + diff --git a/uniapp/pages/tools/schedule/reminder.vue b/uniapp/pages/tools/schedule/reminder.vue index cccd4e7..5bbbd6d 100644 --- a/uniapp/pages/tools/schedule/reminder.vue +++ b/uniapp/pages/tools/schedule/reminder.vue @@ -14,20 +14,52 @@ - - - - {{ d.name }} + + + + + + + {{ monthLabel }} + + + + + {{ monthOpen ? '收起' : '展开月历' }} + + + + + + {{ d.day }} - + v-for="d in weekDays" + :key="d.key" + class="week-item" + @tap="pickWeekDay(d)" + > + {{ d.name }} + {{ d.day }} + + + + + + + 周{{ n }} + + {{ cell.day }} + + @@ -48,7 +80,7 @@ :text="range === 'week' ? '本周暂无日程提醒' : '当天暂无日程提醒'" /> - + {{ shortDayLabel(item.datetime) }} {{ timeText(item.datetime) }} @@ -68,11 +100,18 @@ + + + + + 新增 +