Compare commits

...

2 Commits

Author SHA1 Message Date
XinYuan d62ff8f705 弹窗 7 months ago
XinYuan 5f1a064c12 用户管理 7 months ago
  1. 7
      components.d.ts
  2. 2
      src/pages/Index/Regular/Emergency.vue
  3. 4
      src/pages/Index/Regular/Running.vue
  4. 174
      src/pages/Index/Settings/Users.vue
  5. 5
      src/pages/Index/components/Setting/DelWarn.vue
  6. 79
      src/pages/Index/components/Setting/EnterPinModal.vue
  7. 6
      src/types/Index/User.ts

7
components.d.ts

@ -13,7 +13,11 @@ declare module 'vue' {
ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
ElFooter: typeof import('element-plus/es')['ElFooter']
ElHeader: typeof import('element-plus/es')['ElHeader']
ElIcon: typeof import('element-plus/es')['ElIcon']
ElInput: typeof import('element-plus/es')['ElInput']
ElPopover: typeof import('element-plus/es')['ElPopover']
ElTable: typeof import('element-plus/es')['ElTable']
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
ErrorModal: typeof import('./src/components/dialogs/ErrorModal.vue')['default']
Keyboard: typeof import('./src/components/Keyboard.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
@ -21,4 +25,7 @@ declare module 'vue' {
SimpleKeyboard: typeof import('./src/components/SimpleKeyboard.vue')['default']
StackInfoModal: typeof import('./src/components/dialogs/StackInfoModal.vue')['default']
}
export interface ComponentCustomProperties {
vLoading: typeof import('element-plus/es')['ElLoadingDirective']
}
}

2
src/pages/Index/Regular/Emergency.vue

@ -2,7 +2,7 @@
<div id="add-emergency-container">
<!-- 添加急诊 -->
<div class="page-header">
<img class="page-header-icon" src="@/assets/Index/left.svg" @click="goBack"></img>
<img class="page-header-icon" src="@/assets/Index/left.svg" @click="goBack"/>
<div class="page-header-title">添加急诊</div>
</div>

4
src/pages/Index/Regular/Running.vue

@ -72,6 +72,8 @@ border-radius: 5px;
index+1
}}
<div></div>
<div :style="`margin-top:101px;background-color:${currentIndex == index?'red':'rgb(149, 149, 149)'}`" class="quan">{{ index +1 }}</div>
</div>
<div v-for="(item, index) in incubationPlates" :key="item.sampleId" class="rectangular-item"
:style="[getRotationStyle(item, index), getItemStyle(item)]"
@ -94,7 +96,7 @@ border-radius: 5px;
</div>
<span class="time">{{ getRemainingTime(item) }}</span>
</template>
<div :style="`margin-top:${item.pos=='EMERGENCY'?'35px':'70px'};background-color:${currentIndex == index?'red':'rgb(149, 149, 149)'}`" class="quan">{{ index +1 }}</div>
<div :style="`margin-top:${item.pos=='EMERGENCY'?'35px':'70px'};background-color:${currentIndex == index?'red':'rgb(149, 149, 149)'}`" class="quan">{{ index +1 }}</div>
</div>
</div>
<div class="consumables-container">

174
src/pages/Index/Settings/Users.vue

@ -1,8 +1,8 @@
<template>
<div class="user-management">
<div class="user-table" :key="refreshKey">
<el-table :data="tableData" header-cell-class-name="table-header" row-class-name="table-row">
<el-table-column type="selection" width="80" />
<el-table :data="tableData" header-cell-class-name="table-header" row-class-name="table-row" @selection-change="handleSelectionChange" >
<el-table-column type="selection" width="80"/>
<el-table-column label="用户" property="account" min-width="200" />
<el-table-column label="权限" property="usrRole" min-width="200" />
</el-table>
@ -19,15 +19,15 @@
:message="deleteUserMessage" description="您正在删除用户,请谨慎操作" confirm-text="确认删除" cancel-text="取消删除"
@confirm="handleConfirmDelete" @cancel="handleCancelDelete" />
<DelMessage v-if="delMessageShowModal" v-model:visible="delMessageShowModal" icon="/src/assets/OK.svg"
<DelMessage v-if="delMessageShowModal" v-model="delMessageShowModal" icon="/src/assets/OK.svg"
message="已成功删除用户" :username="selectedUsers[0]?.account" @confirm="handleConfirmMsgDelete" />
<DelWarn v-if="updatePinModal" :visible="updatePinModal" icon="/src/assets/update-pin-icon.svg" title="PIN码更新"
:message="updatePinMessage" description="您正在更改PIN码,请谨慎操作" confirm-text="确认更新" cancel-text="取消更新"
@confirm="handleConfirmUpdatePin" @cancel="handleCancelUpdatePin" />
<EnterPinModal v-if="enterPinModal" :visible="enterPinModal" :loading="updatePinLoading" @confirm="updatePinConfirm"
@cancel="closeEnterPinModal" />
<EnterPinModal v-if="enterPinModal" :visible="enterPinModal" :loading="updatePinLoading" mode="edit" :userId="selectedUsers[0]?.id"
@confirm="updatePinConfirm" @cancel="closeEnterPinModal" />
<DelMessage v-if="updatePinMsgModal" :visible="updatePinMsgModal" icon="/src/assets/OK.svg" message="PIN码更新成功"
:username="selectedUsers[0].account" @confirm="handleConfirmMsg" />
@ -39,7 +39,7 @@
</template>
<template v-else-if="currentStep === 'pin'">
<EnterPinModal :visible="isPinModalVisible" :loading="registerLoading" @confirm="handlePinConfirm"
<EnterPinModal :visible="isPinModalVisible" :loading="registerLoading" mode="add" @confirm="handlePinConfirm"
@cancel="closeModal" />
</template>
@ -51,29 +51,16 @@
<script setup lang="ts">
import type { User } from '../../../types/Index'
import { DelWarn, DelMessage, AddUserModal, EnterPinModal } from '../components'
import { ref, onMounted, computed } from 'vue'
import { ref, onMounted, computed, nextTick } from 'vue'
import {
getUserList,
deleteUser,
userRegister,
changeUserPassword,
} from '../../../services/Index/index'
const tableData = ref<User[]>([
{
id: 1,
account: '管理员',
password: '0000',
usrRole: 'Admin',
isBuiltInUser: true,
},
{
id: 2,
account: '操作员01',
password: '0000',
usrRole: 'Usr',
isBuiltInUser: false,
},
])
import { ElMessage } from 'element-plus'
const tableData = ref<User[]>()
// `newUser` PIN
const newUser = ref({
account: '',
@ -106,6 +93,19 @@ const tips = ref('')
//
const selectedUsers = ref<User[]>([])
const refreshKey = ref(0)
//
const handleSelectionChange = (val: User[]) => {
selectedUsers.value = val;
// tempUser
if (val && val.length > 0) {
tempUser.value = val[0];
} else {
// tempUser
tempUser.value = { id: 0, password: '' };
}
}
//
const fetchUserList = async () => {
const response = await getUserList()
@ -114,44 +114,33 @@ const fetchUserList = async () => {
tableData.value = response.data
} else {
console.log('获取用户列表失败')
ElMessage.error('获取用户列表失败')
}
}
//
// const handleSelectionChange = (val: User[]) => {
// selectedUsers.value = val
// console.log('', val)
// // tempUser
// if (val && val.length > 0) {
// tempUser.value.id = val[0].id
// tempUser.value.password = val[0].password
// } else {
// // tempUser
// tempUser.value.id = 0
// tempUser.value.password = ''
// }
// }
//
const addUser = async () => {
insertUserShowModal.value = true
}
// ( PIN )
const modifyPin = async () => {
if (selectedUsers.value.length === 0) {
//使
isChecked.value = true
ElMessage.warning('请选择一个用户')
return
}
updatePinModal.value = true
}
//
const deleteSelectedUsers = () => {
if (selectedUsers.value.length === 0) {
//使
isChecked.value = true
return
ElMessage.warning('请选择至少一个用户');
return;
}
delShowModal.value = true
delShowModal.value = true;
}
//
onMounted(() => {
fetchUserList()
@ -160,80 +149,101 @@ onMounted(() => {
const handleConfirmDelete = async () => {
try {
const ids = selectedUsers.value.map((user) => user.id)
for (const id of ids) {
const response = await deleteUser({ id })
if (!response || !response.success) {
console.log('删除用户失败')
return
}
const deletePromises = ids.map((id) => deleteUser({ id }))
const results = await Promise.allSettled(deletePromises)
const allSuccess = results.every((result) => result.status === 'fulfilled')
if (allSuccess) {
delShowModal.value = false
selectedUsers.value = []
delMessageShowModal.value = true
ElMessage.success('删除用户成功')
fetchUserList()
} else {
const failedIds = results
.filter((result) => result.status === 'rejected')
.map((_, index) => ids[index])
ElMessage.error(`删除用户失败,ID: ${failedIds.join(', ')}`)
}
delShowModal.value = false
//
// const deletedUsername = selectedUsers.value[0]?.account
//
selectedUsers.value = []
delMessageShowModal.value = true
} catch (error) {
console.error('删除用户时发生错误:', error)
ElMessage.error('删除用户时发生错误')
}
}
const handleCancelDelete = () => {
delShowModal.value = false
}
const handleConfirmMsg = () => {
confirmInsert.value = false
isChecked.value = false
updatePinMsgModal.value = false
fetchUserList()
}
const handleConfirmMsgDelete = () => {
delMessageShowModal.value = false
fetchUserList()
}
//PIN
//
const handleUpdatePin = async () => {
if (selectedUsers.value.length !== 1) {
console.log('请选择一个用户来修改PIN码')
ElMessage.warning('请选择一个用户来修改PIN码')
return
}
const user = tempUser.value
const user = selectedUsers.value[0]
const response = await changeUserPassword({
id: user.id,
password: user.password,
oldpasswd: tempUser.value.password, //
password: tempUser.value.password //
})
if (response && response.success) {
ElMessage.success('PIN码更新成功')
fetchUserList()
} else {
console.log('修改用户权限失败')
ElMessage.error('修改密码失败')
}
}
//pin
const handleConfirmUpdatePin = () => {
if (selectedUsers.value.length !== 1) {
ElMessage.warning('请选择一个用户来修改PIN码')
return
}
updatePinModal.value = false
enterPinModal.value = true
}
//pin
const updatePinConfirm = (val: string) => {
const updatePinConfirm = (parameters: ChangePasswordParams) => {
enterPinModal.value = false
updatePinLoading.value = true
tempUser.value.password = val
handleUpdatePin().then(() => {
changeUserPassword(parameters).then(() => {
updatePinLoading.value = false
updatePinMsgModal.value = true
}).catch(() => {
ElMessage.error('修改密码失败')
updatePinLoading.value = false
})
}
//
const closeEnterPinModal = () => {
enterPinModal.value = false
}
//
const handleCancelUpdatePin = () => {
updatePinModal.value = false
}
//
const handleConfirmInsert = (val: string) => {
const user = tableData.value.find((item) => item.account == val)
@ -250,14 +260,17 @@ const handleConfirmInsert = (val: string) => {
currentStep.value = 'pin'
}
}
const handleCancelInsert = () => {
insertUserShowModal.value = false
}
// `alreadyExist`
const resetAlreadyExist = () => {
isExist.value = false
placeholder.value = '请输入用户名'
}
const handlePinConfirm = (pin: string) => {
// PIN
registerLoading.value = true
@ -266,21 +279,29 @@ const handlePinConfirm = (pin: string) => {
confirmInsert.value = true
registerLoading.value = false
isPinModalVisible.value = false
}).catch((error) => {
ElMessage.error('添加用户失败:' + error.message)
registerLoading.value = false
})
}
const closeModal = () => {
isPinModalVisible.value = false
}
//api
const handleAddUser = async () => {
const res = await userRegister(newUser.value)
if (res && res.success) {
fetchUserList()
} else {
throw new Error('添加用户失败')
}
}
// `account` `Warning`
const selectedUserAccount = computed(() => {
return selectedUsers.value.length > 0 ? selectedUsers.value[0].account : ''
return selectedUsers.value.length > 0? selectedUsers.value[0].account : ''
})
// message
@ -291,6 +312,7 @@ const deleteUserMessage = computed(
() => `是否删除 <strong>${selectedUserAccount.value}</strong> 用户`,
)
</script>
<style scoped lang="less">
.user-management {
width: 100%;
@ -301,7 +323,7 @@ const deleteUserMessage = computed(
display: flex;
flex-direction: column;
.user-table {
.user-table {
flex: 1;
background-color: #fff;
border-radius: 12px;
@ -325,7 +347,7 @@ const deleteUserMessage = computed(
display: none;
}
.el-table__header {
.el-table__header {
th {
background-color: #f5f7fa;
border: none;
@ -340,7 +362,7 @@ const deleteUserMessage = computed(
}
}
.el-table__body {
.el-table__body {
td {
border: none;
height: 60px;
@ -364,10 +386,10 @@ const deleteUserMessage = computed(
}
//
.el-checkbox {
.el-checkbox {
transform: scale(1.5);
.el-checkbox__inner {
.el-checkbox__inner {
border-color: #dcdfe6;
transition: all 0.3s;
@ -378,13 +400,13 @@ const deleteUserMessage = computed(
}
}
.table-footer {
.table-footer {
margin-top: 24px;
display: flex;
justify-content: center;
gap: 20px;
.el-button {
.el-button {
min-width: 160px;
height: 56px;
border-radius: 8px;
@ -422,22 +444,22 @@ const deleteUserMessage = computed(
//
@media screen and (max-width: 768px) {
.user-management {
.user-management {
padding: 10px;
.user-table {
.user-table {
padding: 16px;
.table-footer {
.table-footer {
flex-direction: column;
align-items: stretch;
gap: 12px;
.el-button {
.el-button {
width: 100%;
}
}
}
}
}
</style>
</style>

5
src/pages/Index/components/Setting/DelWarn.vue

@ -14,11 +14,10 @@
</div>
<!-- 操作按钮 -->
<div class="del-warn-footer">
<el-button type="danger" @click="confirmDelete">{{
confirmText
}}</el-button>
<el-button type="primary" @click="cancelDelete">{{
cancelText
}}</el-button> <el-button type="danger" @click="confirmDelete">{{
confirmText
}}</el-button>
</div>
</div>

79
src/pages/Index/components/Setting/EnterPinModal.vue

@ -4,16 +4,37 @@
<div class="modal-container">
<div class="modal-header"></div>
<div class="modal-title">
<span class="title-text">请输入 PIN </span>
<span class="title-text">{{ mode === 'edit'? 'Parameters' : '请输入 PIN 码' }}</span>
</div>
<div class="modal-body">
<div class="input-container">
<input type="password" v-model="pin" placeholder="输入 PIN 码" class="pin-input" />
<div v-if="mode === 'edit'">
<input
type="password"
v-model="form.oldpasswd"
placeholder="oldpasswd"
class="pin-input"
/>
<input
type="password"
v-model="form.password"
placeholder="password"
class="pin-input"
/>
</div>
<div v-else>
<input
type="password"
v-model="pin"
placeholder="输入 PIN 码"
class="pin-input"
/>
</div>
</div>
</div>
<div class="modal-footer">
<el-button type="danger" @click="cancel">取消</el-button>
<el-button type="primary" @click="confirmPin" :loading="loading">确认</el-button>
<el-button type="primary" @click="confirm" :loading="loading">确认</el-button>
</div>
</div>
</div>
@ -21,21 +42,49 @@
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { ref, reactive } from 'vue'
import { ChangePasswordParams } from '../../../../types/Index/User'
// props
const props = defineProps<{
visible: boolean;
loading: boolean;
userId?: number;
mode: 'edit' | 'add';
}>()
defineProps<{ visible: boolean; loading: boolean }>()
const emit = defineEmits<{
(e: 'confirm', pin: string): void
(e: 'confirm', params: ChangePasswordParams | string): void
(e: 'cancel'): void
}>()
//
const form = reactive({
oldpasswd: '',
password: ''
})
const pin = ref('')
const confirmPin = () => {
emit('confirm', pin.value)
//
const confirm = () => {
if (props.mode === 'edit') {
const parameters: ChangePasswordParams = {
id: props.userId,
oldpasswd: form.oldpasswd,
password: form.password
}
emit('confirm', parameters)
} else {
emit('confirm', pin.value)
}
}
//
const cancel = () => {
if (props.mode === 'edit') {
form.oldpasswd = ''
form.password = ''
}
emit('cancel')
}
</script>
@ -80,7 +129,7 @@ const cancel = () => {
justify-content: center;
position: relative;
.modal-header {
.modal-header {
background-color: #528dfe;
height: 8px;
position: absolute;
@ -89,7 +138,7 @@ const cancel = () => {
width: 100%;
}
.modal-title {
.modal-title {
text-align: center;
margin-top: 15px;
font-size: 32px;
@ -97,16 +146,16 @@ const cancel = () => {
font-weight: bold;
}
.modal-body {
.modal-body {
display: flex;
justify-content: center;
padding: 20px;
.input-container {
.input-container {
position: relative;
width: 100%;
.pin-input {
.pin-input {
box-sizing: border-box;
width: 100%;
font-size: 32px;
@ -124,7 +173,7 @@ const cancel = () => {
}
}
.modal-footer {
.modal-footer {
display: flex;
justify-content: space-around;
padding: 20px;
@ -138,4 +187,4 @@ const cancel = () => {
}
}
}
</style>
</style>

6
src/types/Index/User.ts

@ -19,3 +19,9 @@ export interface CurrentUserInfo {
timestamp: number
success: boolean
}
export interface ChangePasswordParams {
id: number; // integer($int32)
oldpasswd: string; // string (query)
password: string; // string (query)
}
Loading…
Cancel
Save