This commit is contained in:
jingna 2026-06-12 15:10:02 +08:00
parent 65c56b8900
commit 050a9571c4
7 changed files with 399 additions and 207 deletions

View File

@ -24,19 +24,8 @@ const keys = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '.', '0', 'del']
const handleKeyPress = (key: string) => { const handleKeyPress = (key: string) => {
if (key === 'del') { if (key === 'del') {
displayValue.value = displayValue.value.slice(0, -1) displayValue.value = displayValue.value.slice(0, -1)
} else if (key === '.') {
const parts = displayValue.value.split('.')
// 34255
if (parts.length < 4 && parts[parts.length - 1] !== '' && parseInt(parts[parts.length - 1]) <= 255) {
displayValue.value += key
}
} else { } else {
const parts = displayValue.value.split('.') displayValue.value += key
const currentPart = parts[parts.length - 1]
// 3255
if (currentPart.length < 3 && parseInt(currentPart + key) <= 255) {
displayValue.value += key
}
} }
} }

View File

@ -0,0 +1,232 @@
<script setup lang="ts">
import { ref, watch } from 'vue'
import { verifyAccessPassword } from '@/api/platform'
interface Props {
visible: boolean
title?: string
}
interface Emits {
(e: 'update:visible', value: boolean): void
(e: 'confirm', password: string): void
(e: 'cancel'): void
}
const props = withDefaults(defineProps<Props>(), {
title: '请输入密码'
})
const emit = defineEmits<Emits>()
const password = ref('')
const errorMessage = ref('')
const isLoading = ref(false)
const keys = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '.', '0', 'del']
//
watch(() => props.visible, (newVal) => {
if (newVal) {
password.value = ''
errorMessage.value = ''
}
})
const handleKeyPress = (key: string) => {
if (key === 'del') {
password.value = password.value.slice(0, -1)
} else {
password.value += key
}
//
errorMessage.value = ''
}
const handleConfirm = () => {
if (!password.value.trim()) {
errorMessage.value = '请输入密码'
return
}
isLoading.value = true
errorMessage.value = ''
verifyAccessPassword(password.value).then((res: any) => {
isLoading.value = false
if (res.data) {
emit('confirm', password.value)
password.value = ''
} else {
errorMessage.value = '密码错误,请重新输入!'
}
}).catch(() => {
isLoading.value = false
errorMessage.value = '校验失败,请重试!'
})
}
const handleCancel = () => {
password.value = ''
emit('cancel')
emit('update:visible', false)
}
const handleClose = () => {
password.value = ''
emit('update:visible', false)
}
</script>
<template>
<el-dialog :model-value="visible" :title="title" :close-on-click-modal="false" :show-close="true" width="320px"
@close="handleClose">
<div class="password-dialog-content">
<div class="label" style="display: flex; align-items: center;">
<span style="min-width: 30px; margin-right: 8px;">密码</span>
<el-input v-model="password" placeholder="请输入密码" @keyup.enter="handleConfirm" class="password-input" />
</div>
<div v-if="errorMessage" class="error-message">{{ errorMessage }}</div>
<div class="password-content">
<div class="keyboard-grid">
<button v-for="key in keys" :key="key" class="key-btn" :class="{ 'action-btn': key === 'del' }"
@click="handleKeyPress(key)">
<img v-if="key === 'del'" style="width: 24px; height: 24px; margin-top: 4px;"
src="@/assets/images/menuicon/jpdel.png" alt="删除" />
<span v-else>{{ key }}</span>
</button>
</div>
<div class="confirm-area">
<button class="cancel-btn" @click="handleCancel">取消</button>
<button class="confirm-btn" @click="handleConfirm" :disabled="isLoading">
<span v-if="isLoading" class="loading">校验中...</span>
<span v-else>确定</span>
</button>
</div>
</div>
</div>
</el-dialog>
</template>
<style scoped lang="scss">
.password-dialog-content {
padding: 0px;
}
.label {
font-size: 14px;
color: #606266;
}
.password-input {
margin-bottom: 8px;
}
.error-message {
color: #f56c6c;
font-size: 12px;
margin-bottom: 12px;
}
.password-content {
padding-top: 10px;
}
.keyboard-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 8px;
}
.key-btn {
height: 36px;
font-size: 18px;
font-weight: 500;
border: none;
border-radius: 4px;
background: #f5f7fa;
color: #303133;
cursor: pointer;
transition: all 0.2s;
&:active {
background: #e4e7ed;
transform: scale(0.98);
}
&.action-btn {
color: #606266;
}
}
.confirm-area {
display: flex;
justify-content: center;
margin-top: 15px;
gap: 20px;
}
.confirm-btn {
width: 80px;
height: 36px;
font-size: 14px;
font-weight: 500;
border: none;
border-radius: 4px;
background: #0099ff;
color: #fff;
cursor: pointer;
transition: all 0.2s;
&:active {
background: #0077cc;
transform: scale(0.98);
}
}
.cancel-btn {
width: 80px;
height: 36px;
font-size: 14px;
font-weight: 500;
border: 1px solid #dcdfe6;
border-radius: 4px;
color: #606266;
cursor: pointer;
transition: all 0.2s;
background: #fff;
&:active {
background: #f5f7fa;
transform: scale(0.98);
}
}
:deep(.el-input__inner) {
text-align: left !important;
}
</style>
<style lang="scss">
// 使 scoped 穿
.password-dialog-content .el-select__wrapper,
.password-dialog-content .el-input__wrapper {
border: 1px solid #dcdfe6 !important;
box-shadow: none !important;
background: #ffffff !important;
text-align: left !important;
}
.password-dialog-content .el-select__wrapper.is-hover,
.password-dialog-content .el-input__wrapper.is-hover,
.password-dialog-content .el-select__wrapper.is-focused,
.password-dialog-content .el-input__wrapper.is-focused {
box-shadow: 0 0 0 2px rgba(0, 153, 255, 0.1) !important;
border-color: #c0c4cc !important;
}
.password-dialog-content .el-input__inner {
text-align: left !important;
}
</style>

View File

@ -1,7 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted } from 'vue' import { ref, onMounted } from 'vue'
import { fetchAiAlarmSetting, saveAiAlarmSetting, verifyAccessPassword } from '@/api/platform' import { fetchAiAlarmSetting, saveAiAlarmSetting, verifyAccessPassword } from '@/api/platform'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage } from 'element-plus'
import PasswordDialog from '@/components/passwordValie.vue'
import NumericKeyboard from '@/components/NumericKeyboard.vue' import NumericKeyboard from '@/components/NumericKeyboard.vue'
interface ChannelItem { interface ChannelItem {
@ -33,6 +34,7 @@ const channelList = ref<ChannelItem[]>([
const nodeOptions = ref(['开出一', '开出二', '开出三', '开出四', '开出五', '开出六', '开出七', '开出八', '开出九', '开出十', '开出十一', '开出十二']) const nodeOptions = ref(['开出一', '开出二', '开出三', '开出四', '开出五', '开出六', '开出七', '开出八', '开出九', '开出十', '开出十一', '开出十二'])
const isswitch = ref(false) const isswitch = ref(false)
const dialogVisible = ref(false) const dialogVisible = ref(false)
const passwordDialogVisible = ref(false)
const keyboardVisible = ref(false) const keyboardVisible = ref(false)
const currentInputValue = ref('') const currentInputValue = ref('')
const currentInputIndex = ref(-1) const currentInputIndex = ref(-1)
@ -52,34 +54,24 @@ const handleKeyboardConfirm = (value: any) => {
} }
const handleSave = () => { const handleSave = () => {
ElMessageBox.prompt('请输入密码', '保存', { passwordDialogVisible.value = true
confirmButtonText: '确定', }
cancelButtonText: '取消',
closeOnClickModal: false, const handlePasswordConfirm = () => {
// inputType: 'password', passwordDialogVisible.value = false
if (isswitch.value) {
return
}
isswitch.value = true
saveAiAlarmSetting(channelList.value).then(res => {
if (res.code === 200) {
ElMessage.success('保存成功')
init()
isswitch.value = false
} else {
ElMessage.error('保存失败')
}
}) })
.then(({ value }) => {
verifyAccessPassword(value).then((res: any) => {
if (res.data) {
if (isswitch.value) {
return
}
isswitch.value = true
saveAiAlarmSetting(channelList.value).then(res => {
if (res.code === 200) {
ElMessage.success('保存成功')
init()
isswitch.value = false
} else {
ElMessage.error('保存失败')
}
})
}else{
isswitch.value = false
dialogVisible.value = true
}
})
})
} }
const init = () => { const init = () => {
@ -160,6 +152,7 @@ onMounted(() => {
:model-value="currentInputValue" :model-value="currentInputValue"
@confirm="handleKeyboardConfirm" @confirm="handleKeyboardConfirm"
/> />
<PasswordDialog v-model:visible="passwordDialogVisible" title="密码验证" @confirm="handlePasswordConfirm" />
</div> </div>
</template> </template>

View File

@ -1,7 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted } from 'vue' import { ref, onMounted } from 'vue'
import { fetchChannelConfig, saveChannelConfig, verifyAccessPassword } from '@/api/platform' import { fetchChannelConfig, saveChannelConfig, verifyAccessPassword } from '@/api/platform'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage } from 'element-plus'
import PasswordDialog from '@/components/passwordValie.vue'
import NumericKeyboard from '@/components/NumericKeyboard.vue' import NumericKeyboard from '@/components/NumericKeyboard.vue'
const channelList = ref<ChannelItem[]>([ const channelList = ref<ChannelItem[]>([
{ ch: 1, singal_type: '4~20mA', line_no: 1, type: 'UA', limit_low: 1, limit_high: 8 }, { ch: 1, singal_type: '4~20mA', line_no: 1, type: 'UA', limit_low: 1, limit_high: 8 },
@ -22,6 +23,7 @@ const lineOptions = ref([{ label: '线路一', value: 1 }, { label: '线路二',
const categoryOptions = ref(['UA', 'UB', 'UC']) const categoryOptions = ref(['UA', 'UB', 'UC'])
const categoryOptions2 = ref(['IA', 'IB', 'IC']) const categoryOptions2 = ref(['IA', 'IB', 'IC'])
const dialogVisible = ref(false) const dialogVisible = ref(false)
const passwordDialogVisible = ref(false)
const isswitch = ref(false) const isswitch = ref(false)
const keyboardVisible = ref(false) const keyboardVisible = ref(false)
const currentInputValue = ref(0) const currentInputValue = ref(0)
@ -62,39 +64,29 @@ const handleKeyboardConfirm = (value: string) => {
} }
const handleSave = () => { const handleSave = () => {
ElMessageBox.prompt('请输入密码', '保存', { passwordDialogVisible.value = true
confirmButtonText: '确定', }
cancelButtonText: '取消',
closeOnClickModal: false, const handlePasswordConfirm = () => {
// inputType: 'password', passwordDialogVisible.value = false
if (isswitch.value) {
return
}
isswitch.value = true
const params = {
ai_channel: channelList.value,
ao_channel: aoChannelList.value,
}
saveChannelConfig(params).then(res => {
if (res.data) {
ElMessage.success('保存成功')
isswitch.value = false
} else {
ElMessage.error('保存失败')
}
}).catch(err => {
isswitch.value = false
}) })
.then(({ value }) => {
verifyAccessPassword(value).then((res: any) => {
if (res.data) {
if (isswitch.value) {
return
}
isswitch.value = true
const params = {
ai_channel: channelList.value,
ao_channel: aoChannelList.value,
}
saveChannelConfig(params).then(res => {
if (res.data) {
ElMessage.success('保存成功')
isswitch.value = false
} else {
ElMessage.error('保存失败')
}
}).catch(err => {
isswitch.value = false
})
} else {
isswitch.value = false
dialogVisible.value = true
}
})
})
} }
function init() { function init() {
fetchChannelConfig().then(res => { fetchChannelConfig().then(res => {
@ -130,7 +122,7 @@ onMounted(() => {
<div class="cell cell-low">低端值</div> <div class="cell cell-low">低端值</div>
<div class="cell cell-high">高端值</div> <div class="cell cell-high">高端值</div>
</div> </div>
<div class="row" v-for="(item, idx ) in channelList" :key="idx"> <div class="row" v-for="(item, idx) in channelList" :key="idx">
<div class="cell cell-no">{{ item.ch }}</div> <div class="cell cell-no">{{ item.ch }}</div>
<div class="cell cell-type" style="background: #ffffff;"> <div class="cell cell-type" style="background: #ffffff;">
<el-input disabled v-model="item.singal_type" placeholder="" /> <el-input disabled v-model="item.singal_type" placeholder="" />
@ -172,11 +164,13 @@ onMounted(() => {
</el-dialog> </el-dialog>
<NumericKeyboard v-model:visible="keyboardVisible" :model-value="currentInputValue" <NumericKeyboard v-model:visible="keyboardVisible" :model-value="currentInputValue"
@confirm="handleKeyboardConfirm" /> @confirm="handleKeyboardConfirm" />
<PasswordDialog v-model:visible="passwordDialogVisible" title="密码验证" @confirm="handlePasswordConfirm" />
</div> </div>
</template> </template>
<style scoped lang="scss"> <style scoped lang="scss">
.ai-channel-container { .ai-channel-container {
width: 100%; width: 100%;
height: 100%; height: 100%;
padding: 15px; padding: 15px;
@ -281,30 +275,30 @@ onMounted(() => {
} }
} }
:deep(.el-select__wrapper),
:deep(.el-input__wrapper) {
border: none !important;
box-shadow: none !important;
background: transparent !important;
text-align: center !important;
}
:deep(.el-select__wrapper.is-hover),
:deep(.el-input__wrapper.is-hover),
:deep(.el-select__wrapper.is-focused),
:deep(.el-input__wrapper.is-focused) {
box-shadow: none !important;
border: none !important;
}
:deep(.el-input__inner) {
text-align: center !important;
font-size: 14px !important;
}
:deep(.el-input.is-disabled .el-input__inner) {
color: #606266;
-webkit-text-fill-color: #606266;
}
// + // +
:deep(.el-select__wrapper),
:deep(.el-input__wrapper) {
border: none !important;
box-shadow: none !important;
background: transparent !important;
text-align: center !important;
}
:deep(.el-select__wrapper.is-hover),
:deep(.el-input__wrapper.is-hover),
:deep(.el-select__wrapper.is-focused),
:deep(.el-input__wrapper.is-focused) {
box-shadow: none !important;
border: none !important;
}
:deep(.el-input__inner) {
text-align: center !important;
font-size: 14px !important;
}
:deep(.el-input.is-disabled .el-input__inner) {
color: #606266;
-webkit-text-fill-color: #606266;
}
</style> </style>

View File

@ -1,7 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted } from 'vue' import { ref, onMounted } from 'vue'
import { fetchChannelConfig, saveChannelConfig, verifyAccessPassword } from '@/api/platform' import { fetchChannelConfig, saveChannelConfig, verifyAccessPassword } from '@/api/platform'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage } from 'element-plus'
import PasswordDialog from '@/components/passwordValie.vue'
import NumericKeyboard from '@/components/NumericKeyboard.vue' import NumericKeyboard from '@/components/NumericKeyboard.vue'
interface ChannelItem { interface ChannelItem {
ch: number ch: number
@ -29,6 +30,7 @@ const lineOptions = ref([{ label: '线路一', value: 1 }, { label: '线路二',
const categoryOptions = ref(['UA', 'UB', 'UC']) const categoryOptions = ref(['UA', 'UB', 'UC'])
const categoryOptions2 = ref(['IA', 'IB', 'IC']) const categoryOptions2 = ref(['IA', 'IB', 'IC'])
const dialogVisible = ref(false) const dialogVisible = ref(false)
const passwordDialogVisible = ref(false)
const aiChannelList = ref([]) const aiChannelList = ref([])
const currentInputType = ref('') const currentInputType = ref('')
const currentInputIndex = ref(-1) const currentInputIndex = ref(-1)
@ -77,39 +79,29 @@ function init() {
} }
const isswitch = ref(false) const isswitch = ref(false)
const handleSave = () => { const handleSave = () => {
ElMessageBox.prompt('请输入密码', '保存', { passwordDialogVisible.value = true
confirmButtonText: '确定', }
cancelButtonText: '取消',
closeOnClickModal: false, const handlePasswordConfirm = () => {
// inputType: 'password', passwordDialogVisible.value = false
if (isswitch.value) {
return
}
isswitch.value = true
const params = {
ai_channel: aiChannelList.value,
ao_channel: channelList.value,
}
saveChannelConfig(params).then(res => {
if (res.code === 200) {
ElMessage.success('保存成功')
isswitch.value = false
} else {
ElMessage.error('保存失败')
}
}).catch(err => {
isswitch.value = false
}) })
.then(({ value }) => {
verifyAccessPassword(value).then((res: any) => {
if (res.data) {
if (isswitch.value) {
return
}
isswitch.value = true
const params = {
ai_channel: aiChannelList.value,
ao_channel: channelList.value,
}
saveChannelConfig(params).then(res => {
if (res.code === 200) {
ElMessage.success('保存成功')
isswitch.value = false
} else {
ElMessage.error('保存失败')
}
}).catch(err => {
isswitch.value = false
})
} else {
isswitch.value = false
dialogVisible.value = true
}
})
})
} }
onMounted(() => { onMounted(() => {
init() init()
@ -169,6 +161,7 @@ onMounted(() => {
</el-dialog> </el-dialog>
<NumericKeyboard v-model:visible="keyboardVisible" :model-value="currentInputValue" <NumericKeyboard v-model:visible="keyboardVisible" :model-value="currentInputValue"
@confirm="handleKeyboardConfirm" /> @confirm="handleKeyboardConfirm" />
<PasswordDialog v-model:visible="passwordDialogVisible" title="密码验证" @confirm="handlePasswordConfirm" />
</div> </div>
</template> </template>

View File

@ -1,8 +1,9 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted } from 'vue' import { ref, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage } from 'element-plus'
import { fetchDeviceNet, fetchDevicePort, saveDeviceNetConfig, saveDevicePortConfig, verifyAccessPassword, fetchChannelConfig } from '@/api/platform' import { fetchDeviceNet, fetchDevicePort, saveDeviceNetConfig, saveDevicePortConfig, verifyAccessPassword, fetchChannelConfig } from '@/api/platform'
import NumericKeyboard from '@/components/NumericKeyboard.vue' import NumericKeyboard from '@/components/NumericKeyboard.vue'
import PasswordDialog from '@/components/passwordValie.vue'
// //
const formData: any = ref({ const formData: any = ref({
@ -68,6 +69,7 @@ const rtuProtocolOptions = [
const isswitch = ref(false) const isswitch = ref(false)
const dialogVisible = ref(false) const dialogVisible = ref(false)
const keyboardVisible = ref(false) const keyboardVisible = ref(false)
const passwordDialogVisible = ref(false)
const currentInputValue = ref('') const currentInputValue = ref('')
const currentInputKey = ref('') const currentInputKey = ref('')
const currentInputIndex = ref(0) const currentInputIndex = ref(0)
@ -86,55 +88,45 @@ const handleKeyboardConfirm = (value: string) => {
} }
// //
const handleSave = () => { const handleSave = () => {
ElMessageBox.prompt('请输入密码', '保存', { passwordDialogVisible.value = true
confirmButtonText: '确定', }
cancelButtonText: '取消',
closeOnClickModal: false, //
}) const handlePasswordConfirm = () => {
.then(({ value }) => { saveDeviceNetConfig(formData.value).then((res: any) => {
verifyAccessPassword(value).then((res: any) => { if (isswitch.value) {
if (res.data) { return
saveDeviceNetConfig(formData.value).then((res: any) => { }
if (isswitch.value) { isswitch.value = true
return if (res.code == 200) {
} saveDevicePortConfig(formData2.value).then((res: any) => {
isswitch.value = true if (res.code == 200) {
if (res.code == 200) { ElMessage({
saveDevicePortConfig(formData2.value).then((res: any) => { type: 'success',
if (res.code == 200) { message: `保存成功`,
ElMessage({ })
type: 'success', isswitch.value = false
message: `保存成功`, } else {
}) ElMessage({
isswitch.value = false type: 'error',
} else { message: '串口设置保存失败',
ElMessage({
type: 'error',
message: '串口设置保存失败',
})
isswitch.value = false
}
})
} else {
ElMessage({
type: 'error',
message: '常规配置保存失败',
})
isswitch.value = false
}
}) })
} else {
isswitch.value = false isswitch.value = false
dialogVisible.value = true
} }
}) })
}) } else {
.catch(() => { ElMessage({
// ElMessage({ type: 'error',
// type: 'info', message: '常规配置保存失败',
// message: '', })
// }) isswitch.value = false
}) }
})
}
//
const handlePasswordCancel = () => {
//
} }
const config: any = ref({}) const config: any = ref({})
const handleChange = (val: any) => { const handleChange = (val: any) => {
@ -263,6 +255,12 @@ onMounted(() => {
<el-button type="primary" @click="dialogVisible = false">确定</el-button> <el-button type="primary" @click="dialogVisible = false">确定</el-button>
</template> </template>
</el-dialog> </el-dialog>
<PasswordDialog
v-model:visible="passwordDialogVisible"
title="密码验证"
@confirm="handlePasswordConfirm"
@cancel="handlePasswordCancel"
/>
<NumericKeyboard v-model:visible="keyboardVisible" :model-value="currentInputValue" <NumericKeyboard v-model:visible="keyboardVisible" :model-value="currentInputValue"
@confirm="handleKeyboardConfirm"> @confirm="handleKeyboardConfirm">
</NumericKeyboard> </NumericKeyboard>

View File

@ -1,7 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted } from 'vue' import { ref, onMounted } from 'vue'
import { fetchLineAlarmSetting, saveLineAlarmSetting, verifyAccessPassword } from '@/api/platform' import { fetchLineAlarmSetting, saveLineAlarmSetting, verifyAccessPassword } from '@/api/platform'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage } from 'element-plus'
import PasswordDialog from '@/components/passwordValie.vue'
import NumericKeyboard from '@/components/NumericKeyboard.vue' import NumericKeyboard from '@/components/NumericKeyboard.vue'
const lineTabs = ref([ const lineTabs = ref([
{ {
@ -220,36 +221,27 @@ const init = () => {
} }
const isswitch = ref(false) const isswitch = ref(false)
const dialogVisible = ref(false) const dialogVisible = ref(false)
const passwordDialogVisible = ref(false)
const handleSave = () => { const handleSave = () => {
console.log(infoList.value) console.log(infoList.value)
ElMessageBox.prompt('请输入密码', '保存', { passwordDialogVisible.value = true
confirmButtonText: '确定', }
cancelButtonText: '取消',
closeOnClickModal: false, const handlePasswordConfirm = () => {
// inputType: 'password', passwordDialogVisible.value = false
if (isswitch.value) {
return
}
isswitch.value = true
saveLineAlarmSetting(infoList.value).then(res => {
if (res.code === 200) {
ElMessage.success('保存成功')
init()
isswitch.value = false
} else {
ElMessage.error('保存失败')
}
}) })
.then(({ value }) => {
verifyAccessPassword(value).then((res: any) => {
if (res.data) {
if (isswitch.value) {
return
}
isswitch.value = true
saveLineAlarmSetting(infoList.value).then(res => {
if (res.code === 200) {
ElMessage.success('保存成功')
init()
isswitch.value = false
} else {
ElMessage.error('保存失败')
}
})
} else {
isswitch.value = false
dialogVisible.value = true
}
})
})
} }
</script> </script>
@ -433,6 +425,7 @@ const handleSave = () => {
</el-dialog> </el-dialog>
<NumericKeyboard v-model:visible="keyboardVisible" :model-value="currentInputValue" <NumericKeyboard v-model:visible="keyboardVisible" :model-value="currentInputValue"
@confirm="handleKeyboardConfirm"></NumericKeyboard> @confirm="handleKeyboardConfirm"></NumericKeyboard>
<PasswordDialog v-model:visible="passwordDialogVisible" title="密码验证" @confirm="handlePasswordConfirm" />
</div> </div>
</template> </template>