backend增加租户简称登录

This commit is contained in:
2026-07-17 11:00:33 +08:00
parent dcf06db11b
commit 2232ef6f3c
14 changed files with 916 additions and 746 deletions
@@ -15,6 +15,16 @@
</div>
</div>
<div class="editor-toolbar">
<el-switch
v-model="pinned"
inline-prompt
active-text="置顶"
inactive-text="置顶"
:disabled="loading"
/>
</div>
<div class="editor-body">
<UmoEditor v-model="noteContent" />
</div>
@@ -38,6 +48,7 @@ const emit = defineEmits(['save-success', 'create-success']);
const noteTitle = ref('');
const noteContent = ref('');
const pinned = ref(false);
const loading = ref(false);
const isNew = ref(false);
@@ -47,6 +58,7 @@ const loadNote = async () => {
isNew.value = true;
noteTitle.value = '新建笔记';
noteContent.value = '';
pinned.value = false;
return;
}
@@ -58,6 +70,7 @@ const loadNote = async () => {
if (response.code === 200) {
noteTitle.value = response.data.title || '无标题';
noteContent.value = response.data.content || '';
pinned.value = Number(response.data.pinned) === 1;
} else {
ElMessage.error('加载笔记失败');
}
@@ -84,6 +97,7 @@ const handleSave = async () => {
const response = await createNotebook({
title: noteTitle.value,
content: noteContent.value,
pinned: pinned.value ? 1 : 0,
});
if (response.code === 200) {
@@ -98,6 +112,7 @@ const handleSave = async () => {
const response = await updateNotebook(props.noteId, {
title: noteTitle.value,
content: noteContent.value,
pinned: pinned.value ? 1 : 0,
});
if (response.code === 200) {
@@ -175,6 +190,15 @@ onMounted(() => {
}
}
.editor-toolbar {
min-height: 42px;
padding: 8px 20px;
display: flex;
align-items: center;
border-bottom: 1px solid var(--el-border-color-lighter);
background: var(--el-bg-color);
}
.editor-body {
flex: 1;
padding: 20px;
@@ -28,6 +28,15 @@
>
<div class="note-item-header">
<span class="note-title">{{ note.title || '无标题' }}</span>
<el-tag
v-if="Number(note.pinned) === 1"
class="pinned-tag"
size="small"
type="warning"
effect="plain"
>
置顶
</el-tag>
<el-dropdown trigger="click" @command="(cmd) => handleNoteAction(cmd, note)">
<el-icon class="note-more"><MoreFilled /></el-icon>
<template #dropdown>
@@ -305,6 +314,7 @@ onMounted(() => {
.note-title {
flex: 1;
min-width: 0;
font-size: 14px;
font-weight: 500;
color: var(--el-text-color-primary);
@@ -313,6 +323,11 @@ onMounted(() => {
text-overflow: ellipsis;
}
.pinned-tag {
flex-shrink: 0;
margin-left: 8px;
}
.note-more {
margin-left: 8px;
color: var(--el-text-color-secondary);
+6 -1
View File
@@ -78,7 +78,7 @@ func (c *BackendNotebookController) List() {
total, _ := qs.Count()
var list []models.BackendNotebook
_, err = qs.OrderBy("-update_time", "-create_time").
_, err = qs.OrderBy("-pinned", "-id").
Limit(pageSize).Offset((page - 1) * pageSize).
All(&list)
if err != nil && err != orm.ErrNoRows {
@@ -137,6 +137,7 @@ func (c *BackendNotebookController) Create() {
var payload struct {
Title string `json:"title"`
Content string `json:"content"`
Pinned int8 `json:"pinned"`
}
if err := json.Unmarshal(raw, &payload); err != nil {
c.nbJsonErr(400, 400, "参数错误")
@@ -153,6 +154,7 @@ func (c *BackendNotebookController) Create() {
Tid: claims.TenantId,
Title: payload.Title,
Content: payload.Content,
Pinned: payload.Pinned,
UserID: &userID,
UserName: &claims.Username,
IsDeleted: 0,
@@ -190,6 +192,7 @@ func (c *BackendNotebookController) Update() {
var payload struct {
Title string `json:"title"`
Content string `json:"content"`
Pinned int8 `json:"pinned"`
}
if err := json.Unmarshal(raw, &payload); err != nil {
c.nbJsonErr(400, 400, "参数错误")
@@ -219,6 +222,7 @@ func (c *BackendNotebookController) Update() {
Update(map[string]interface{}{
"title": payload.Title,
"content": payload.Content,
"pinned": payload.Pinned,
"update_time": now,
})
if err != nil {
@@ -228,6 +232,7 @@ func (c *BackendNotebookController) Update() {
note.Title = payload.Title
note.Content = payload.Content
note.Pinned = payload.Pinned
note.UpdateTime = &now
c.nbOk(note)
}
+6 -1
View File
@@ -86,7 +86,7 @@ func (c *PlatformNotebookController) List() {
}
var list []models.PlatformNotebook
_, err = qs.OrderBy("-update_time", "-create_time").
_, err = qs.OrderBy("-pinned", "-id").
Limit(pageSize).
Offset((page - 1) * pageSize).
All(&list)
@@ -158,6 +158,7 @@ func (c *PlatformNotebookController) Create() {
var payload struct {
Title string `json:"title"`
Content string `json:"content"`
Pinned int8 `json:"pinned"`
}
if err := json.Unmarshal(raw, &payload); err != nil {
@@ -174,6 +175,7 @@ func (c *PlatformNotebookController) Create() {
note := &models.PlatformNotebook{
Title: payload.Title,
Content: payload.Content,
Pinned: payload.Pinned,
UserID: &userID,
UserName: &claims.Username,
IsDeleted: 0,
@@ -213,6 +215,7 @@ func (c *PlatformNotebookController) Update() {
var payload struct {
Title string `json:"title"`
Content string `json:"content"`
Pinned int8 `json:"pinned"`
}
if err := json.Unmarshal(raw, &payload); err != nil {
@@ -248,6 +251,7 @@ func (c *PlatformNotebookController) Update() {
Update(map[string]interface{}{
"title": payload.Title,
"content": payload.Content,
"pinned": payload.Pinned,
"update_time": now,
})
@@ -258,6 +262,7 @@ func (c *PlatformNotebookController) Update() {
note.Title = payload.Title
note.Content = payload.Content
note.Pinned = payload.Pinned
note.UpdateTime = &now
jsonResponse(&c.Controller, 200, 200, "更新成功", note)
+1
View File
@@ -7,6 +7,7 @@ type PlatformNotebook struct {
ID uint64 `orm:"column(id);pk;auto" json:"id"`
Title string `orm:"column(title);size(255)" json:"title"`
Content string `orm:"column(content);type(longtext);null" json:"content"`
Pinned int8 `orm:"column(pinned);default(0)" json:"pinned"`
UserID *uint64 `orm:"column(user_id);null" json:"user_id"`
UserName *string `orm:"column(user_name);size(100);null" json:"user_name"`
IsDeleted int8 `orm:"column(is_deleted);default(0)" json:"is_deleted"`
+14 -13
View File
@@ -3,19 +3,20 @@ package models
import "time"
type SystemTenant struct {
ID uint64 `orm:"column(id);pk;auto" json:"id"`
TenantCode string `orm:"column(tenant_code);size(32)" json:"tenant_code"`
TenantName string `orm:"column(tenant_name);size(128)" json:"tenant_name"`
ContactPerson *string `orm:"column(contact_person);size(64);null" json:"contact_person"`
ContactPhone *string `orm:"column(contact_phone);size(20);null" json:"contact_phone"`
ContactEmail *string `orm:"column(contact_email);size(128);null" json:"contact_email"`
Address *string `orm:"column(address);size(255);null" json:"address"`
Worktime *string `orm:"column(worktime);size(255);null" json:"worktime"`
Status int8 `orm:"column(status);default(1)" json:"status"`
Remark *string `orm:"column(remark);size(512);null" json:"remark"`
CreateTime time.Time `orm:"column(create_time);auto_now_add;type(datetime)" json:"create_time"`
UpdateTime time.Time `orm:"column(update_time);auto_now;type(datetime)" json:"update_time"`
DeleteTime *time.Time `orm:"column(delete_time);type(datetime);null" json:"delete_time"`
ID uint64 `orm:"column(id);pk;auto" json:"id"`
TenantCode string `orm:"column(tenant_code);size(32)" json:"tenant_code"`
TenantName string `orm:"column(tenant_name);size(128)" json:"tenant_name"`
TenantShortName *string `orm:"column(tenant_short_name);size(128);null" json:"tenant_short_name"`
ContactPerson *string `orm:"column(contact_person);size(64);null" json:"contact_person"`
ContactPhone *string `orm:"column(contact_phone);size(20);null" json:"contact_phone"`
ContactEmail *string `orm:"column(contact_email);size(128);null" json:"contact_email"`
Address *string `orm:"column(address);size(255);null" json:"address"`
Worktime *string `orm:"column(worktime);size(255);null" json:"worktime"`
Status int8 `orm:"column(status);default(1)" json:"status"`
Remark *string `orm:"column(remark);size(512);null" json:"remark"`
CreateTime time.Time `orm:"column(create_time);auto_now_add;type(datetime)" json:"create_time"`
UpdateTime time.Time `orm:"column(update_time);auto_now;type(datetime)" json:"update_time"`
DeleteTime *time.Time `orm:"column(delete_time);type(datetime);null" json:"delete_time"`
}
func (m *SystemTenant) TableName() string {
+2 -2
View File
@@ -98,8 +98,8 @@ func SendBackendLoginCode(tenantName, account, channel string) error {
return errors.New("仅支持短信或邮箱验证码")
}
var tenant models.SystemTenant
if err := models.Orm.QueryTable(new(models.SystemTenant)).Filter("tenant_name", tenantName).One(&tenant); err != nil {
tenant, err := findTenantByLoginName(tenantName)
if err != nil {
return errors.New("租户不存在")
}
+1 -4
View File
@@ -93,10 +93,7 @@ func BackendLogin(tenantName, account, password string) (string, *PlatformLoginU
return "", nil, errors.New("租户名称、用户名或密码不能为空")
}
var tenant models.SystemTenant
err := models.Orm.QueryTable(new(models.SystemTenant)).
Filter("tenant_name", tenantName).
One(&tenant)
tenant, err := findTenantByLoginName(tenantName)
if err != nil {
return "", nil, errors.New("租户不存在")
}
+43
View File
@@ -0,0 +1,43 @@
package services
import (
"strings"
"github.com/beego/beego/v2/client/orm"
"server/models"
)
/* findTenantByLoginName 根据租户简称短名或编码查找租户
*
* 当前表结构中 tenant_name 的业务含义就是租户简称同时兼容
* tenant_short_name tenant_code 两个历史/备用登录标识
*/
func findTenantByLoginName(loginName string) (*models.SystemTenant, error) {
loginName = strings.TrimSpace(loginName)
if loginName == "" {
return nil, orm.ErrNoRows
}
// tenant_name 的业务含义是租户简称。使用 TRIM 兼容历史数据中字段值
// 前后存在空格的情况;参数通过 SetArgs 绑定,避免 SQL 注入。
tenant := &models.SystemTenant{}
query := `
SELECT id, tenant_code, tenant_name, tenant_short_name,
contact_person, contact_phone, contact_email, address,
worktime, status, remark, create_time, update_time, delete_time
FROM yz_system_tenant
WHERE (TRIM(tenant_name) = TRIM(?) OR
TRIM(tenant_short_name) = TRIM(?) OR
TRIM(tenant_code) = TRIM(?))
AND status <> 0
ORDER BY id ASC
LIMIT 1`
err := models.Orm.Raw(query).
SetArgs(loginName, loginName, loginName).
QueryRow(tenant)
if err != nil {
return nil, err
}
return tenant, nil
}
@@ -15,6 +15,16 @@
</div>
</div>
<div class="editor-toolbar">
<el-switch
v-model="pinned"
inline-prompt
active-text="置顶"
inactive-text="置顶"
:disabled="loading"
/>
</div>
<div class="editor-body">
<UmoEditor v-model="noteContent" />
</div>
@@ -38,6 +48,7 @@ const emit = defineEmits(['save-success', 'create-success']);
const noteTitle = ref('');
const noteContent = ref('');
const pinned = ref(false);
const loading = ref(false);
const isNew = ref(false);
@@ -47,6 +58,7 @@ const loadNote = async () => {
isNew.value = true;
noteTitle.value = '新建笔记';
noteContent.value = '';
pinned.value = false;
return;
}
@@ -58,6 +70,7 @@ const loadNote = async () => {
if (response.code === 200) {
noteTitle.value = response.data.title || '无标题';
noteContent.value = response.data.content || '';
pinned.value = Number(response.data.pinned) === 1;
} else {
ElMessage.error('加载笔记失败');
}
@@ -84,6 +97,7 @@ const handleSave = async () => {
const response = await createNotebook({
title: noteTitle.value,
content: noteContent.value,
pinned: pinned.value ? 1 : 0,
});
if (response.code === 200) {
@@ -98,6 +112,7 @@ const handleSave = async () => {
const response = await updateNotebook(props.noteId, {
title: noteTitle.value,
content: noteContent.value,
pinned: pinned.value ? 1 : 0,
});
if (response.code === 200) {
@@ -175,6 +190,15 @@ onMounted(() => {
}
}
.editor-toolbar {
min-height: 42px;
padding: 8px 20px;
display: flex;
align-items: center;
border-bottom: 1px solid var(--el-border-color-lighter);
background: var(--el-bg-color);
}
.editor-body {
flex: 1;
padding: 20px;
@@ -28,6 +28,15 @@
>
<div class="note-item-header">
<span class="note-title">{{ note.title || '无标题' }}</span>
<el-tag
v-if="Number(note.pinned) === 1"
class="pinned-tag"
size="small"
type="warning"
effect="plain"
>
置顶
</el-tag>
<el-dropdown trigger="click" @command="(cmd) => handleNoteAction(cmd, note)">
<el-icon class="note-more"><MoreFilled /></el-icon>
<template #dropdown>
@@ -305,6 +314,7 @@ onMounted(() => {
.note-title {
flex: 1;
min-width: 0;
font-size: 14px;
font-weight: 500;
color: var(--el-text-color-primary);
@@ -313,6 +323,11 @@ onMounted(() => {
text-overflow: ellipsis;
}
.pinned-tag {
flex-shrink: 0;
margin-left: 8px;
}
.note-more {
margin-left: 8px;
color: var(--el-text-color-secondary);
+14
View File
@@ -0,0 +1,14 @@
-- 记事本表增加置顶字段(兼容已有数据库)
-- 已存在字段时请跳过对应 ALTER 语句。
ALTER TABLE `yz_platform_notebook`
ADD COLUMN `pinned` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否置顶 0-否 1-是' AFTER `content`;
ALTER TABLE `yz_platform_notebook`
ADD KEY `idx_pinned` (`pinned`);
ALTER TABLE `yz_backend_notebook`
ADD COLUMN `pinned` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否置顶 0-否 1-是' AFTER `content`;
ALTER TABLE `yz_backend_notebook`
ADD KEY `idx_pinned` (`pinned`);
+2
View File
@@ -3,6 +3,7 @@ CREATE TABLE IF NOT EXISTS `yz_platform_notebook` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`title` varchar(255) NOT NULL DEFAULT '' COMMENT '笔记标题',
`content` longtext COMMENT '笔记内容(HTML格式)',
`pinned` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否置顶 0-否 1-是',
`user_id` bigint(20) unsigned DEFAULT NULL COMMENT '创建用户ID',
`user_name` varchar(100) DEFAULT NULL COMMENT '创建用户名',
`is_deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否删除 0-否 1-是',
@@ -11,6 +12,7 @@ CREATE TABLE IF NOT EXISTS `yz_platform_notebook` (
`delete_time` datetime DEFAULT NULL COMMENT '删除时间',
PRIMARY KEY (`id`),
KEY `idx_user_id` (`user_id`),
KEY `idx_pinned` (`pinned`),
KEY `idx_create_time` (`create_time`),
KEY `idx_is_deleted` (`is_deleted`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='平台记事本表';
+24
View File
@@ -0,0 +1,24 @@
FAIL _/E_/Demos/DemoOwns/Go/yunzerwebsiteallinone/go [setup failed]
FAIL _/E_/Demos/DemoOwns/Go/yunzerwebsiteallinone/go/controllers [setup failed]
FAIL _/E_/Demos/DemoOwns/Go/yunzerwebsiteallinone/go/middleware [setup failed]
FAIL _/E_/Demos/DemoOwns/Go/yunzerwebsiteallinone/go/models [setup failed]
FAIL _/E_/Demos/DemoOwns/Go/yunzerwebsiteallinone/go/pkg/jwtutil [setup failed]
FAIL _/E_/Demos/DemoOwns/Go/yunzerwebsiteallinone/go/pkg/tokenprobe [setup failed]
FAIL _/E_/Demos/DemoOwns/Go/yunzerwebsiteallinone/go/routers [setup failed]
FAIL _/E_/Demos/DemoOwns/Go/yunzerwebsiteallinone/go/routers/api [setup failed]
FAIL _/E_/Demos/DemoOwns/Go/yunzerwebsiteallinone/go/routers/app [setup failed]
FAIL _/E_/Demos/DemoOwns/Go/yunzerwebsiteallinone/go/routers/backend [setup failed]
FAIL _/E_/Demos/DemoOwns/Go/yunzerwebsiteallinone/go/routers/index [setup failed]
FAIL _/E_/Demos/DemoOwns/Go/yunzerwebsiteallinone/go/routers/platform [setup failed]
FAIL _/E_/Demos/DemoOwns/Go/yunzerwebsiteallinone/go/services [setup failed]
FAIL backend [setup failed]
FAIL docs [setup failed]
FAIL frontend [setup failed]
FAIL go [setup failed]
FAIL platform [setup failed]
FAIL sql [setup failed]
FAIL uniapp [setup failed]
? _/E_/Demos/DemoOwns/Go/yunzerwebsiteallinone/go/pkg/passwordutil [no test files]
? _/E_/Demos/DemoOwns/Go/yunzerwebsiteallinone/go/pkg/versionutil [no test files]
? _/E_/Demos/DemoOwns/Go/yunzerwebsiteallinone/go/version [no test files]
FAIL