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 42b333b..bbb472c 100644
--- a/uniapp/pages/login/login.vue
+++ b/uniapp/pages/login/login.vue
@@ -1,161 +1,195 @@
-
-
-
-
+
+
+
+
+
+
+
+
- 云泽统一认证
- 欢迎回来,开启云泽服务
+ {{ navTitle }}
+
-
-
-
-
- 选择企业
- 该账号已加入多家企业,请选择要进入的空间
+
+
+
+
+
+
+ 云泽统一认证
+ 一次登录,全平台通行
+
-
- {{ errorMsg }}
-
-
-
-
-
-
-
-
- {{ item.tenant_name || `企业${item.tid}` }}
- {{ item.name ? `${item.name} · ` : '' }}企业ID {{ item.tid }}
-
-
+
+
+
+
+ 欢迎登录
+ 使用微信手机号,一键完成身份认证
-
-
- 不是我的账号?切换账号
-
-
-
-
-
-
- {{ showMiniLogin && activeTab === 'account' ? '账号登录' : '欢迎登录' }}
- {{ panelSub }}
-
-
-
- {{ errorMsg }}
-
-
-
-
-
-
-
-
-
- 微信安全授权,快捷登录云泽统一认证
+
+ {{ errorMsg }}
-
- 账号登录
+
+
+
+
+
+
+ 首次使用请先用账号密码登录一次,自动完成微信绑定后即可一键登录
+
+
+
+ 正在加载登录方式…
+
+
+
+
+
+
+ 使用账号密码登录
+
+
-
-
-
-
- ‹ 微信一键登录
-
-
- 账号
-
-
+
+
+
+ 欢迎回来
+ 请输入您的账号与密码以继续
-
-
- 密码
-
-
-
-
+ {{ errorMsg }}
+
+
+
+ 账号
+
+
+
-
-
-
-
-
- 请先阅读并勾选同意《用户协议》和《隐私政策》
-
-
+
+
+
+ 请选择企业
+ 该账号已加入多家企业,请选择要进入的空间
+
+
+
+ {{ errorMsg }}
+
+
+
+
+
+
+
+
+ {{ item.tenant_name || `企业${item.tid}` }}
+ {{ item.name ? `${item.name} · ` : '' }}企业ID {{ item.tid }}
+
+
+
+
+
+
+
+
+
+
+
+ 登录即表示同意
+ 《用户协议》
+ 和
+ 《隐私政策》
+
+
+
+
+
+
+ 请先阅读并勾选同意《用户协议》和《隐私政策》
+
+
+
-
-
-
- 登录即表示同意
- 《用户协议》
- 和
- 《隐私政策》
-
+
@@ -189,9 +223,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)
@@ -207,36 +257,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 '微信授权,安全快捷地登录'
- }
- if (platform.value === 'mp-weixin' && showMiniLogin.value && activeTab.value === 'account') {
- 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()) {
@@ -248,8 +327,6 @@ onMounted(async () => {
if (remembered.rememberMe) {
rememberMe.value = true
account.value = remembered.account
- // 记住了账号,默认落在账号密码 Tab 更顺手
- activeTab.value = 'account'
}
loadVerifyConfig()
@@ -278,6 +355,10 @@ async function loadMiniLoginConfig() {
} catch {
showMiniLogin.value = false
}
+ // 服务端未开通一键登录:直接落到账号密码视图
+ if (!showMiniLogin.value && step.value === 'main') {
+ step.value = 'account'
+ }
}
/* ==================== 登录主流程 ==================== */
@@ -383,9 +464,10 @@ function chooseTenant(item) {
})
}
+/** 从「选择企业」退回账号密码视图 */
function backToAccount() {
clearAuthState()
- step.value = 'password'
+ step.value = 'account'
errorMsg.value = ''
}
@@ -509,13 +591,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)
}
@@ -538,11 +621,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 || '登录失败,请稍后重试'
}
/** 勾选/取消用户协议:勾选后自动收起未勾选提示 */
@@ -605,60 +691,123 @@ function goForget() {
+/* ---------- 页脚 ---------- */
+.foot-tip {
+ position: relative;
+ z-index: 2;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 8rpx;
+ margin-top: 40rpx;
+}
+
+.foot-tip-text {
+ font-size: 22rpx;
+ color: $color-text-muted;
+}
+
\ No newline at end of file
diff --git a/uniapp/pages/nav/nav.vue b/uniapp/pages/nav/nav.vue
index c4b6cd3..0f35da1 100644
--- a/uniapp/pages/nav/nav.vue
+++ b/uniapp/pages/nav/nav.vue
@@ -4,34 +4,17 @@
- 工作空间
- 选择一个应用,开始今天的工作
+ YUNZE WORKSPACE
+ 工作台
+ {{ user.account || '我的账号' }}
-
-
-
- 当前公司
- {{ user.tenant || '云泽平台' }}
-
- {{ user.account }}
-
-
-
-
-
-
-
- 切换公司
- 完成
-
- 选择后将切换当前工作空间
-
-
- {{ item.tenant_name || `企业${item.tid}` }}{{ Number(item.tid) === currentTid ? '当前工作空间' : '切换到此公司' }}
-
-
+
+
+ 当前租户{{ user.tenant || '云泽平台' }}
+ 切换
+ 选择一个业务系统,开始高效工作
@@ -78,7 +61,7 @@ import { mpHeadPad } from '@/utils/mpHead.js'
const headPad = mpHeadPad()
import { onShow } from '@dcloudio/uni-app'
-import { isLoggedIn, getTenants, getTid, setAuthTokens, setTid, setTenantName } 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'
@@ -106,9 +89,7 @@ const loadError = ref('')
const user = ref({})
const modules = ref([])
const menus = ref([])
-const tenants = ref([])
-const currentTid = ref(0)
-const tenantPickerVisible = ref(false)
+const tenants = ref(getTenants())
const switchingTenant = ref(false)
/** 叶子菜单(可直接跳转的功能页),已锁定的过滤掉 */
@@ -146,7 +127,6 @@ const cards = computed(() => {
})
})
-const enabledCount = computed(() => cards.value.filter((c) => !c.locked).length)
/* ==================== 数据加载 ==================== */
@@ -170,6 +150,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 端该模块首页。
@@ -258,89 +273,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-title {
- font-size: 46rpx;
+.head-eyebrow {
+ display: block;
+ margin-bottom: 8rpx;
+ font-size: 18rpx;
font-weight: 700;
- color: #193d61;
+ letter-spacing: 3rpx;
+ color: #6e9de5;
+}
+
+.head-title {
+ display: block;
+ font-size: 44rpx;
+ font-weight: 700;
+ color: #17345f;
letter-spacing: 1rpx;
}
-.head-caption {
- display: block;
- margin-top: 10rpx;
- font-size: 24rpx;
- color: #8aa2b8;
-}
-
-.tenant-switcher {
- margin-top: 28rpx;
- padding: 20rpx 22rpx;
+.account-chip {
display: flex;
align-items: center;
- gap: 16rpx;
- border: 1rpx solid rgba(255, 255, 255, 0.92);
- border-radius: 24rpx;
- background: rgba(255, 255, 255, 0.78);
- box-shadow: 0 12rpx 32rpx rgba(81, 133, 176, 0.08);
+ gap: 9rpx;
+ padding: 12rpx 17rpx;
+ border-radius: 30rpx;
+ background: rgba(255,255,255,.85);
+ color: #526b8d;
+ font-size: 22rpx;
+}
- &.selectable:active { background: #f4faff; }
+.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: 68rpx;
- height: 68rpx;
- flex-shrink: 0;
- border-radius: 20rpx;
- background: #eaf5ff;
+ width: 64rpx;
+ height: 64rpx;
+ border-radius: 16rpx;
display: flex;
align-items: center;
justify-content: center;
+ background: linear-gradient(145deg, #69a5ff, #3478f6);
}
-.tenant-current {
- flex: 1;
- min-width: 0;
-}
-
-.tenant-label {
- display: block;
- margin-bottom: 5rpx;
- font-size: 20rpx;
- color: #94aabe;
-}
+.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;
- font-size: 28rpx;
- font-weight: 600;
- color: #294a68;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.tenant-account {
- max-width: 180rpx;
- font-size: 21rpx;
- color: #8da3b7;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
+ margin-top: 22rpx;
+ font-size: 23rpx;
+ color: #8295b0;
}
/* ============ 内容区 ============ */
@@ -349,101 +355,8 @@ onShow(() => {
min-height: 0;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
- padding: 8rpx $page-padding-x 0;
-}
-
-.tenant-mask {
- position: fixed;
- z-index: 99;
- left: 0;
- top: 0;
- right: 0;
- bottom: 0;
- background: rgba(18, 42, 68, 0.32);
- display: flex;
- align-items: flex-end;
-}
-
-.tenant-sheet {
- width: 100%;
- max-height: 72vh;
- overflow-y: auto;
- padding: 38rpx 32rpx calc(env(safe-area-inset-bottom, 0px) + 40rpx);
- box-sizing: border-box;
- border-radius: 36rpx 36rpx 0 0;
- background: linear-gradient(180deg, #f5faff 0%, #ffffff 24%);
-}
-
-.sheet-head {
- display: flex;
- align-items: center;
- justify-content: space-between;
-}
-
-.sheet-title {
- font-size: 32rpx;
- font-weight: 600;
- color: #203b56;
-}
-
-.sheet-close {
- font-size: 25rpx;
- color: #398fe7;
- padding: 10rpx;
-}
-
-.sheet-sub {
- display: block;
- margin: 8rpx 0 20rpx;
- font-size: 23rpx;
- color: #8aa0b4;
-}
-
-.tenant-option {
- display: flex;
- align-items: center;
- gap: 18rpx;
- padding: 20rpx 16rpx;
- border-radius: 18rpx;
- border: 1rpx solid #edf3f8;
- margin-top: 12rpx;
-
- &.current {
- background: #f2f8ff;
- border-color: #cfe5fa;
- }
-
- &.disabled { opacity: 0.6; }
-}
-
-.tenant-option-icon {
- width: 64rpx;
- height: 64rpx;
- border-radius: 18rpx;
- background: #eaf5ff;
- display: flex;
- align-items: center;
- justify-content: center;
-}
-
-.tenant-option-info {
- flex: 1;
- min-width: 0;
-}
-
-.tenant-option-name,
-.tenant-option-meta { display: block; }
-
-.tenant-option-name {
- font-size: 27rpx;
- font-weight: 500;
- color: #294763;
-}
-
-.tenant-option-meta {
- margin-top: 5rpx;
- font-size: 22rpx;
- color: #91a5b8;
+ padding: 20rpx $page-padding-x 0;
+ background: #f5f8fd;
}
/* ============ 失败提示 ============ */
@@ -510,7 +423,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 @@
+
+
+
+
+ 平台信息
+
+
+ 平台名称 *
+
+
+
+
+ 登录网址
+
+
+
+
+ 平台备注
+
+
+
+
+
+
+
+ 挂载账号列表
+
+
+ 添加账号
+
+
+
+
+
+ 账号 {{ idx + 1 }}
+
+
+ 删除
+
+
+
+
+ 账号 / 用户名
+
+
+
+
+
+ 登录密码
+
+
+ 随机生成
+
+
+
+
+
+
+
+
+
+
+
+ 注册信息
+
+
+
+
+ 账号备注
+
+
+
+
+
+ 暂无账号,点击右上角「添加账号」
+
+
+
+
+
+
+
+
+
+
+
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 @@
+
+
+
+
+
+
+
+
+
+ 共 {{ total }} 条
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ store.platform || '未命名平台' }}
+
+ {{ store.url }}
+ 未填写网址
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 账号
+ {{ acc.username || '-' }}
+
+
+
+
+
+ 密码
+ {{ shownPwd[accKey(store, idx)] ? (acc.password || '-') : '••••••••' }}
+
+
+
+
+
+
+
+
+ 注册信息
+ {{ acc.registration_info }}
+
+
+ 备注
+ {{ acc.remark }}
+
+
+ 该平台暂无账号
+
+
+
+
+
+
+ 编辑
+
+
+
+ 删除
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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 @@
+
+
+
+
+ 日程内容 *
+
+
+
+
+ 日程时间 *
+
+
+
+ {{ form.date || '选择日期' }}
+
+
+
+
+
+ {{ form.time || '选择时间' }}
+
+
+
+
+
+
+
+ 提前提醒
+
+
+ {{ minutesLabels[minutesIndex] }}
+
+
+
+
+
+
+ 提醒渠道 *
+
+
+ {{ opt.label }}
+
+
+ 可多选,至少选择一个提醒渠道
+
+
+
+
+ 重复提醒间隔
+
+
+ {{ repeatLabels[repeatIndex] }}
+
+
+
+ 仅邮件 / Bark 渠道支持重复提醒
+
+
+
+ 最大发送次数
+
+
+ {{ maxSendLabels[maxSendIndex] }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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 }}
+
+
+
+
+
+
{{ 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 @@
+
+
+
+
+ 新增
+