修复部分样式bug

This commit is contained in:
2025-12-29 16:14:28 +08:00
parent b1da484431
commit e635b2e160
7 changed files with 77 additions and 39 deletions

View File

@@ -12,6 +12,8 @@ export const useAuthStore = defineStore('auth', {
this.username = username this.username = username
localStorage.setItem('isLoggedIn', 'true') localStorage.setItem('isLoggedIn', 'true')
localStorage.setItem('username', username) localStorage.setItem('username', username)
// 记住密码:按需求将密码持久化到 localStorage
localStorage.setItem('rememberedPassword', password)
return true return true
} }
return false return false

View File

@@ -1,7 +1,7 @@
<template> <template>
<div class="conversation-list-container"> <div class="conversation-list-container">
<!-- 筛选表单折叠面板 --> <!-- 筛选表单折叠面板 -->
<el-collapse v-model="activeCollapse" class="filter-collapse"> <el-collapse v-model="activeCollapse" class="filter-collapse" size="small">
<el-collapse-item name="filter"> <el-collapse-item name="filter">
<template #title> <template #title>
<div class="collapse-header"> <div class="collapse-header">
@@ -14,7 +14,8 @@
</template> </template>
<el-form :model="filterForm" inline label-width="80px" size="small"> <el-form :model="filterForm" inline label-width="80px" size="small">
<el-form-item label="快捷范围"> <el-form-item label="快捷范围">
<el-select v-model="filterForm.quickRange" placeholder="请选择" clearable style="width: 150px" @change="handleQuickRangeChange"> <el-select v-model="filterForm.quickRange" placeholder="请选择" clearable style="width: 150px"
@change="handleQuickRangeChange">
<el-option label="今天" value="today"></el-option> <el-option label="今天" value="today"></el-option>
<el-option label="最近3天" value="last3"></el-option> <el-option label="最近3天" value="last3"></el-option>
<el-option label="最近7天" value="last7"></el-option> <el-option label="最近7天" value="last7"></el-option>
@@ -23,27 +24,13 @@
</el-form-item> </el-form-item>
<el-form-item label="开始日期"> <el-form-item label="开始日期">
<el-date-picker <el-date-picker v-model="filterForm.startDate" type="date" format="YYYY-MM-DD" value-format="YYYY-MM-DD"
v-model="filterForm.startDate" clearable class="date-picker" @change="handleManualDateChange" />
type="date"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
clearable
class="date-picker"
@change="handleManualDateChange"
/>
</el-form-item> </el-form-item>
<el-form-item label="结束日期"> <el-form-item label="结束日期">
<el-date-picker <el-date-picker v-model="filterForm.endDate" type="date" format="YYYY-MM-DD" value-format="YYYY-MM-DD"
v-model="filterForm.endDate" clearable class="date-picker" @change="handleManualDateChange" />
type="date"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
clearable
class="date-picker"
@change="handleManualDateChange"
/>
</el-form-item> </el-form-item>
<el-form-item label="用户"> <el-form-item label="用户">
@@ -74,22 +61,18 @@
<el-scrollbar :style="{ height: scrollbarHeight }" @scroll="handleScroll"> <el-scrollbar :style="{ height: scrollbarHeight }" @scroll="handleScroll">
<div v-loading="loading" class="descriptions-container"> <div v-loading="loading" class="descriptions-container">
<div v-for="(item, index) in conversationList" :key="index" class="descriptions-item"> <div v-for="(item, index) in conversationList" :key="index" class="descriptions-item">
<el-descriptions :column="1" size="small" label-width="0px"> <el-text type="info" size="small">
<el-descriptions-item label=""> {{ formatDateTime(item.recordTime) }} | {{ item.userName }} | {{ item.department }} |
{{ formatDateTime(item.recordTime) }} | {{ item.userName }} | {{ item.department }} <el-icon v-if="item.messageType === 1"><OfficeBuilding /></el-icon>
<el-tag :type="item.messageType === 1 ? 'success' : ''"> <el-icon v-else><User /></el-icon>
{{ item.messageType === 1 ? '公有' : '私有' }} |
</el-tag> <el-icon v-if="item.sendMethod === 'text'"><EditPen /></el-icon>
<el-tag :type="item.sendMethod === '文字' ? 'success' : ''"> <el-icon v-else><Microphone /></el-icon>
{{ item.sendMethod === 'text' ? '文字' : '语音' }}{{ item.speakingTime ? ' | ' + item.speakingTime + '' : {{ item.speakingTime ? item.speakingTime + 's' : '' }}
'' </el-text>
}}
</el-tag> <br />
</el-descriptions-item> <el-text size="small">{{ item.conversationContent }}</el-text>
<el-descriptions-item label="">
{{ item.conversationContent }}
</el-descriptions-item>
</el-descriptions>
</div> </div>
<!-- 加载更多提示 --> <!-- 加载更多提示 -->
@@ -112,7 +95,7 @@ import { ref, reactive, onMounted, computed, watch } from 'vue'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import request from '../utils/request' import request from '../utils/request'
import { formatPhoneNumber, formatDateTime, formatTimestamp } from '../utils/formatters' import { formatPhoneNumber, formatDateTime, formatTimestamp } from '../utils/formatters'
import { Loading } from '@element-plus/icons-vue' import { Loading, OfficeBuilding, User, EditPen, Microphone } from '@element-plus/icons-vue'
// 加载状态 // 加载状态
const loading = ref(false) const loading = ref(false)
@@ -436,7 +419,7 @@ onMounted(() => {
/* 每个Descriptions项的样式 */ /* 每个Descriptions项的样式 */
.descriptions-item { .descriptions-item {
margin-bottom: 20px; margin-bottom: 2px;
border-radius: 4px; border-radius: 4px;
overflow: hidden; overflow: hidden;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);

View File

@@ -102,6 +102,11 @@ const handleLogin = async () => {
// 组件挂载时添加键盘监听 // 组件挂载时添加键盘监听
onMounted(() => { onMounted(() => {
// 自动回填:如果曾经成功登录过,直接从 localStorage 取出密码
const rememberedPassword = localStorage.getItem('rememberedPassword')
if (rememberedPassword) {
loginForm.password = rememberedPassword
}
window.addEventListener('keypress', handleKeyPress) window.addEventListener('keypress', handleKeyPress)
}) })

View File

@@ -0,0 +1,17 @@
# Change: 管理端登录记住密码localStorage 自动回填)
## Why
后台管理登录当前每次都需要手动输入密码,重复操作影响效率。需要提供“曾经输入过一次密码后,后续自动记住并回填”的机制。
## What Changes
- 登录成功后,将本次输入的密码写入 `localStorage`
- 下次进入登录页时,自动从 `localStorage` 读取并回填密码,使用户无需再次手动输入。
## Security Note
该机制会将密码以明文形式存储在浏览器 `localStorage`,存在被同机用户或恶意脚本读取的风险。本变更仅按当前产品需求实现;建议后续升级为服务端鉴权与 token 机制,避免存储明文密码。
## Impact
- Affected specs: `openspec/specs/backend-admin/spec.md`
- Affected code:
- `admin-web/src/views/Login.vue`
- `admin-web/src/store/auth.js`

View File

@@ -0,0 +1,16 @@
## MODIFIED Requirements
### Requirement: 用户认证(前端验证)
管理端登录 SHALL 支持“记住密码”机制:
- 当管理员首次成功登录后,系统将本次输入的密码持久化到浏览器 `localStorage`
- 后续访问登录页时,系统自动从 `localStorage` 读取并回填密码,使管理员无需再次手动输入
#### Scenario: 首次登录后记住密码
- **WHEN** 管理员使用正确用户名/密码登录成功
- **THEN** 系统将密码写入 `localStorage`
#### Scenario: 进入登录页自动回填
- **WHEN** 管理员再次进入登录页
- **AND** `localStorage` 中存在已保存的密码
- **THEN** 页面自动回填密码输入框

View File

@@ -0,0 +1,7 @@
# Tasks — 管理端登录记住密码localStorage
- [x] 更新 delta spec`openspec/changes/add-admin-login-remember-password/specs/backend-admin/spec.md`
- [x] 更新现行 spec`openspec/specs/backend-admin/spec.md`(登录能力增加记住密码)
- [x] 登录实现:成功登录后写入 `localStorage`(保存密码)
- [x] 登录页初始化:读取 `localStorage` 自动回填密码
- [ ] 前端验证:确认刷新页面后不需要重新输入密码

View File

@@ -28,6 +28,9 @@
### Requirement: 用户认证(前端验证) ### Requirement: 用户认证(前端验证)
前端管理网站 SHALL 提供管理员登录功能,使用前端验证方式。 前端管理网站 SHALL 提供管理员登录功能,使用前端验证方式。
实现补充(效率优化):
- 系统 SHOULD 提供“记住密码”机制:当管理员成功登录过一次后,将密码保存到浏览器 `localStorage` 并在下次进入登录页时自动回填,从而无需重复输入。
#### Scenario: 管理员登录 #### Scenario: 管理员登录
- **WHEN** 管理员访问登录页面 - **WHEN** 管理员访问登录页面
- **THEN** 显示登录表单(用户名、密码字段) - **THEN** 显示登录表单(用户名、密码字段)
@@ -35,6 +38,11 @@
- **AND** 登录成功后跳转到首页 - **AND** 登录成功后跳转到首页
- **AND** 登录状态保存在 Pinia store 中 - **AND** 登录状态保存在 Pinia store 中
#### Scenario: 记住密码并自动回填
- **WHEN** 管理员成功登录一次
- **THEN** 系统将本次输入的密码写入 `localStorage`
- **AND** 下次进入登录页时自动回填密码输入框
#### Scenario: 登录验证失败 #### Scenario: 登录验证失败
- **WHEN** 管理员输入错误的用户名或密码 - **WHEN** 管理员输入错误的用户名或密码
- **THEN** 显示错误提示信息 - **THEN** 显示错误提示信息