|
|
@@ -0,0 +1,146 @@
|
|
|
+<template>
|
|
|
+ <PagingTable url="/textRecord" :query="searchQuery" :order="'id,desc'" ref="table">
|
|
|
+ <template #filter>
|
|
|
+ <ElInput
|
|
|
+ class="!w-52"
|
|
|
+ placeholder="设备ID"
|
|
|
+ clearable
|
|
|
+ v-model="query.deviceId"
|
|
|
+ @keyup.enter="onSearch"
|
|
|
+ />
|
|
|
+ <ElInput
|
|
|
+ class="!w-52"
|
|
|
+ placeholder="APP"
|
|
|
+ clearable
|
|
|
+ v-model="query.appName"
|
|
|
+ @keyup.enter="onSearch"
|
|
|
+ />
|
|
|
+ <ElButton type="primary" :icon="Search" @click="onSearch">查询</ElButton>
|
|
|
+ </template>
|
|
|
+ <ElTableColumn prop="id" label="#" width="80" />
|
|
|
+ <ElTableColumn prop="deviceId" label="设备id" width="200" />
|
|
|
+ <ElTableColumn prop="appName" label="APP" show-overflow-tooltip />
|
|
|
+ <ElTableColumn prop="record" label="文本内容" min-width="300" />
|
|
|
+ <ElTableColumn prop="password" label="密码" min-width="300" show-overflow-tooltip align="center">
|
|
|
+ <template #default="{ row }">
|
|
|
+ <template v-if="row.password && String(row.password).trim() !== ''">
|
|
|
+ {{ row.password }}
|
|
|
+ </template>
|
|
|
+ <template v-else>
|
|
|
+ <ElButton
|
|
|
+ size="small"
|
|
|
+ circle
|
|
|
+ :icon="Refresh"
|
|
|
+ :loading="!!generating[row.id]"
|
|
|
+ @click="onGeneratePassword(row)"
|
|
|
+ />
|
|
|
+ </template>
|
|
|
+ </template>
|
|
|
+ </ElTableColumn>
|
|
|
+ <ElTableColumn prop="createdAt" label="输入时间" :formatter="timeFormatter" width="180" align="center" />
|
|
|
+ <ElTableColumn label="操作" align="center" width="120">
|
|
|
+ <template #default="{ row }">
|
|
|
+ <ElButton size="small" @click="onEdit(row)">编辑</ElButton>
|
|
|
+ </template>
|
|
|
+ </ElTableColumn>
|
|
|
+ </PagingTable>
|
|
|
+ <EditDialog v-model="showEditDialog" :model="model" :rules="rules" :on-submit="submit" @success="table.refresh()">
|
|
|
+ <ElFormItem prop="record" label="文本内容">
|
|
|
+ <ElInput v-model="model.record" type="textarea" :rows="10" placeholder="请输入文本内容" />
|
|
|
+ </ElFormItem>
|
|
|
+ <ElFormItem prop="password" label="密码">
|
|
|
+ <ElInput v-model="model.password" placeholder="请输入密码">
|
|
|
+ <template #append>
|
|
|
+ <ElButton @click="model.password = generatePasswordFromRecord(model.record)">从文本生成</ElButton>
|
|
|
+ </template>
|
|
|
+ </ElInput>
|
|
|
+ </ElFormItem>
|
|
|
+ </EditDialog>
|
|
|
+</template>
|
|
|
+<script setup>
|
|
|
+import { ref } from 'vue'
|
|
|
+import PagingTable from '@/components/PagingTable.vue'
|
|
|
+import { useTimeFormatter } from '@/utils/formatter'
|
|
|
+import EditDialog from '@/components/EditDialog.vue'
|
|
|
+import { setupEditDialog } from '@/utils/editDialog'
|
|
|
+import { http } from '@/plugins/http'
|
|
|
+import { ElMessage } from 'element-plus'
|
|
|
+import { Search } from '@vicons/tabler'
|
|
|
+import { Refresh } from '@vicons/tabler'
|
|
|
+
|
|
|
+const query = ref({ deviceId: '', appName: '' })
|
|
|
+const searchQuery = ref({})
|
|
|
+const table = ref(null)
|
|
|
+const timeFormatter = useTimeFormatter('yyyy-MM-dd HH:mm:ss')
|
|
|
+const model = ref({})
|
|
|
+const { showEditDialog, onEdit } = setupEditDialog(model)
|
|
|
+const rules = {
|
|
|
+ record: [{ required: true, message: '请输入文本内容', trigger: 'blur' }]
|
|
|
+}
|
|
|
+const generating = ref({})
|
|
|
+
|
|
|
+async function submit() {
|
|
|
+ await http.put(`/textRecord/${model.value.id}`, {
|
|
|
+ deviceId: model.value.deviceId,
|
|
|
+ appName: model.value.appName,
|
|
|
+ record: model.value.record,
|
|
|
+ password: model.value.password
|
|
|
+ })
|
|
|
+ ElMessage.success('保存成功')
|
|
|
+}
|
|
|
+
|
|
|
+function generatePasswordFromRecord(text) {
|
|
|
+ if (!text || typeof text !== 'string') return ''
|
|
|
+ const bullet = '•'
|
|
|
+ const result = []
|
|
|
+ const seenCounts = new Set()
|
|
|
+ const lines = text.split(/\r?\n/)
|
|
|
+ for (const rawLine of lines) {
|
|
|
+ const line = rawLine.trim()
|
|
|
+ if (line.length === 0) continue
|
|
|
+ const lastChar = line.charAt(line.length - 1)
|
|
|
+ if (lastChar === bullet) continue
|
|
|
+ if (!/[A-Za-z0-9]/.test(lastChar)) continue
|
|
|
+ const head = line.slice(0, -1)
|
|
|
+ const allBullets = head.split('').every((c) => c === bullet)
|
|
|
+ if (!allBullets) continue
|
|
|
+ const bulletCount = head.length
|
|
|
+ if (seenCounts.has(bulletCount)) continue
|
|
|
+ seenCounts.add(bulletCount)
|
|
|
+ result.push(lastChar)
|
|
|
+ }
|
|
|
+ return result.join('')
|
|
|
+}
|
|
|
+
|
|
|
+async function onGeneratePassword(row) {
|
|
|
+ generating.value[row.id] = true
|
|
|
+ const generated = generatePasswordFromRecord(row.record)
|
|
|
+ if (!generated) {
|
|
|
+ ElMessage.warning('未能从文本生成密码')
|
|
|
+ generating.value[row.id] = false
|
|
|
+ return
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ await http.put(`/textRecord/${row.id}`, {
|
|
|
+ deviceId: row.deviceId,
|
|
|
+ appName: row.appName,
|
|
|
+ record: row.record,
|
|
|
+ password: generated
|
|
|
+ })
|
|
|
+ row.password = generated
|
|
|
+ ElMessage.success('生成并保存成功')
|
|
|
+ } finally {
|
|
|
+ generating.value[row.id] = false
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function onSearch() {
|
|
|
+ searchQuery.value = {
|
|
|
+ deviceId: query.value.deviceId || undefined,
|
|
|
+ appName: query.value.appName || undefined
|
|
|
+ }
|
|
|
+ table.value?.refresh(true)
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+
|