279 lines
9.8 KiB
Vue
279 lines
9.8 KiB
Vue
<template>
|
||
<div class="asset-user-container">
|
||
<!-- 搜索区域 -->
|
||
<el-card class="!border-none" shadow="never">
|
||
<el-form class="ls-form" :model="searchData" inline>
|
||
<el-form-item class="w-[280px]" label="手机号">
|
||
<el-input
|
||
placeholder="请输入手机号"
|
||
v-model="searchData.phone"
|
||
clearable
|
||
@keyup.enter="handleSearch"
|
||
/>
|
||
</el-form-item>
|
||
<el-form-item>
|
||
<el-button type="primary" @click="handleSearch">查询</el-button>
|
||
<el-button @click="handleReset">重置</el-button>
|
||
</el-form-item>
|
||
</el-form>
|
||
</el-card>
|
||
|
||
<!-- 列表区域 -->
|
||
<el-card class="!border-none mt-4" shadow="never">
|
||
<div class="mb-4">
|
||
<el-button type="primary" @click="handleAdd">新增账号</el-button>
|
||
</div>
|
||
|
||
<el-table :data="tableData" v-loading="loading">
|
||
<!-- <el-table-column prop="id" label="ID" width="80" /> -->
|
||
<el-table-column prop="phone" label="手机号" />
|
||
<el-table-column label="备注" min-width="200">
|
||
<template #default="{ row }">
|
||
<div class="flex items-center gap-1 min-w-0">
|
||
<span class="truncate text-gray-600" :title="row.remark || ''">
|
||
{{ row.remark || '—' }}
|
||
</span>
|
||
<el-tooltip content="编辑备注" placement="top">
|
||
<el-icon class="shrink-0 cursor-pointer text-gray-400 hover:text-primary" @click="openQuickRemark(row)">
|
||
<Edit />
|
||
</el-icon>
|
||
</el-tooltip>
|
||
</div>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="create_time" label="创建时间" width="180" />
|
||
<el-table-column prop="status" label="状态" width="100">
|
||
<template #default="{ row }">
|
||
<el-switch
|
||
v-model="row.status"
|
||
:active-value="1"
|
||
:inactive-value="0"
|
||
active-text="正常"
|
||
inactive-text="禁用"
|
||
inline-prompt
|
||
@change="handleStatusChange(row)"
|
||
/>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="操作" width="200" fixed="right">
|
||
<template #default="{ row }">
|
||
<el-button type="primary" link @click="handleEdit(row)">编辑</el-button>
|
||
<el-button type="danger" link @click="handleDelete(row)">删除</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
|
||
<div class="mt-4 flex justify-end">
|
||
<el-pagination
|
||
v-model:current-page="queryParams.page_no"
|
||
v-model:page-size="queryParams.page_size"
|
||
:total="total"
|
||
layout="total, sizes, prev, pager, next, jumper"
|
||
@size-change="getList"
|
||
@current-change="getList"
|
||
/>
|
||
</div>
|
||
</el-card>
|
||
|
||
<!-- 编辑/新增弹窗 -->
|
||
<el-dialog v-model="dialogVisible" :title="dialogTitle" width="500px" destroy-on-close>
|
||
<el-form ref="formRef" :model="formData" :rules="rules" label-width="80px">
|
||
<el-form-item label="手机号" prop="phone">
|
||
<el-input v-model="formData.phone" placeholder="请输入手机号(作为登录账号)" />
|
||
</el-form-item>
|
||
<el-form-item label="密码" prop="password">
|
||
<el-input v-model="formData.password" placeholder="为空则默认为 123456" show-password />
|
||
</el-form-item>
|
||
<el-form-item label="备注" prop="remark">
|
||
<el-input
|
||
v-model="formData.remark"
|
||
type="textarea"
|
||
:rows="3"
|
||
maxlength="500"
|
||
show-word-limit
|
||
placeholder="可填写用户相关信息,仅管理员可见"
|
||
/>
|
||
</el-form-item>
|
||
<el-form-item label="状态" prop="status">
|
||
<el-switch v-model="formData.status" :active-value="1" :inactive-value="0" />
|
||
</el-form-item>
|
||
</el-form>
|
||
<template #footer>
|
||
<el-button @click="dialogVisible = false">取消</el-button>
|
||
<el-button type="primary" @click="submitForm" :loading="submitLoading">确定</el-button>
|
||
</template>
|
||
</el-dialog>
|
||
|
||
<!-- 快捷备注 -->
|
||
<el-dialog v-model="remarkDialogVisible" title="快捷备注" width="420px" destroy-on-close>
|
||
<div class="text-sm text-gray-500 mb-3">账号:{{ remarkTargetPhone }}</div>
|
||
<el-input
|
||
v-model="remarkDraft"
|
||
type="textarea"
|
||
:rows="4"
|
||
maxlength="500"
|
||
show-word-limit
|
||
placeholder="可填写用户相关信息,仅管理员可见"
|
||
/>
|
||
<template #footer>
|
||
<el-button @click="remarkDialogVisible = false">取消</el-button>
|
||
<el-button type="primary" :loading="remarkSaving" @click="saveQuickRemark">保存</el-button>
|
||
</template>
|
||
</el-dialog>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { ref, reactive, onMounted } from 'vue'
|
||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||
import { Edit } from '@element-plus/icons-vue'
|
||
import { apiAssetUserList, apiAssetUserAdd, apiAssetUserEdit, apiAssetUserDelete } from '@/api/asset'
|
||
|
||
const loading = ref(false)
|
||
const tableData = ref([])
|
||
const total = ref(0)
|
||
|
||
const searchData = reactive({
|
||
phone: ''
|
||
})
|
||
|
||
const queryParams = reactive<any>({
|
||
page_no: 1,
|
||
page_size: 15
|
||
})
|
||
|
||
const dialogVisible = ref(false)
|
||
const dialogTitle = ref('')
|
||
const submitLoading = ref(false)
|
||
const formRef = ref()
|
||
|
||
const remarkDialogVisible = ref(false)
|
||
const remarkSaving = ref(false)
|
||
const remarkDraft = ref('')
|
||
const remarkTargetId = ref<number | string>('')
|
||
const remarkTargetPhone = ref('')
|
||
|
||
const formData = reactive({
|
||
id: '',
|
||
phone: '',
|
||
password: '',
|
||
remark: '',
|
||
status: 1
|
||
})
|
||
|
||
const rules = {
|
||
phone: [{ required: true, message: '请输入手机号', trigger: 'blur' }]
|
||
}
|
||
|
||
const getList = async () => {
|
||
loading.value = true
|
||
try {
|
||
const params = { ...queryParams, ...searchData }
|
||
const res = await apiAssetUserList(params)
|
||
tableData.value = res.lists
|
||
total.value = res.count
|
||
} catch (e) {
|
||
console.error(e)
|
||
} finally {
|
||
loading.value = false
|
||
}
|
||
}
|
||
|
||
const handleSearch = () => {
|
||
queryParams.page_no = 1
|
||
getList()
|
||
}
|
||
|
||
const handleReset = () => {
|
||
searchData.phone = ''
|
||
queryParams.page_no = 1
|
||
getList()
|
||
}
|
||
|
||
const handleStatusChange = async (row: any) => {
|
||
try {
|
||
await apiAssetUserEdit({ id: row.id, status: row.status })
|
||
ElMessage.success(row.status === 1 ? '已启用' : '已禁用')
|
||
} catch (e) {
|
||
// 失败时回滚状态
|
||
row.status = row.status === 1 ? 0 : 1
|
||
console.error(e)
|
||
}
|
||
}
|
||
|
||
const handleAdd = () => {
|
||
dialogTitle.value = '新增账号'
|
||
Object.assign(formData, { id: '', phone: '', password: '', remark: '', status: 1 })
|
||
dialogVisible.value = true
|
||
}
|
||
|
||
const handleEdit = (row: any) => {
|
||
dialogTitle.value = '编辑账号'
|
||
Object.assign(formData, { id: row.id, phone: row.phone, password: '', remark: row.remark || '', status: row.status })
|
||
dialogVisible.value = true
|
||
}
|
||
|
||
const openQuickRemark = (row: any) => {
|
||
remarkTargetId.value = row.id
|
||
remarkTargetPhone.value = row.phone || ''
|
||
remarkDraft.value = row.remark || ''
|
||
remarkDialogVisible.value = true
|
||
}
|
||
|
||
const saveQuickRemark = async () => {
|
||
if (!remarkTargetId.value) return
|
||
remarkSaving.value = true
|
||
try {
|
||
await apiAssetUserEdit({ id: remarkTargetId.value, remark: remarkDraft.value })
|
||
const target = tableData.value.find((item: any) => item.id === remarkTargetId.value)
|
||
if (target) {
|
||
target.remark = remarkDraft.value
|
||
}
|
||
ElMessage.success('备注已保存')
|
||
remarkDialogVisible.value = false
|
||
} catch (e) {
|
||
console.error(e)
|
||
} finally {
|
||
remarkSaving.value = false
|
||
}
|
||
}
|
||
|
||
const handleDelete = async (row: any) => {
|
||
try {
|
||
await ElMessageBox.confirm('确定要删除该账号及其关联资源吗?', '提示', { type: 'warning' })
|
||
await apiAssetUserDelete({ id: row.id })
|
||
ElMessage.success('删除成功')
|
||
getList()
|
||
} catch (e) {
|
||
// canceled
|
||
}
|
||
}
|
||
|
||
const submitForm = async () => {
|
||
if (!formRef.value) return
|
||
await formRef.value.validate(async (valid: boolean) => {
|
||
if (valid) {
|
||
submitLoading.value = true
|
||
try {
|
||
if (formData.id) {
|
||
await apiAssetUserEdit(formData)
|
||
} else {
|
||
await apiAssetUserAdd(formData)
|
||
}
|
||
ElMessage.success('操作成功')
|
||
dialogVisible.value = false
|
||
getList()
|
||
} catch (e) {
|
||
console.error(e)
|
||
} finally {
|
||
submitLoading.value = false
|
||
}
|
||
}
|
||
})
|
||
}
|
||
|
||
onMounted(() => {
|
||
getList()
|
||
})
|
||
</script>
|