用户搜索,导入,密码,修改

This commit is contained in:
zhaoyz 2024-04-11 17:55:47 +08:00
parent 628244785b
commit 37c49d5f4f
10 changed files with 261 additions and 105 deletions

View File

@ -2,7 +2,7 @@ import request from "@/utils/request";
export const fileUploadUrl = '/admin/sys-file/upload' export const fileUploadUrl = '/admin/sys-file/upload'
export const handleHttpUpload = (options: any) => { export function handleHttpUpload(options: any) {
let formData = new FormData(); let formData = new FormData();
formData.append('file', options.file); formData.append('file', options.file);
formData.append('dir', options.dir) formData.append('dir', options.dir)
@ -23,3 +23,25 @@ export const handleHttpUpload = (options: any) => {
} }
}) })
} }
export function handleHttpUploadUrl(options: any, url: string | undefined) {
let formData = new FormData();
formData.append('file', options.file);
formData.append('dir', options.dir)
return new Promise((resolve, reject) => {
try {
request({
url: url,
method: 'post',
headers: {
'Content-Type': 'multipart/form-data',
},
data: formData,
}).then((res: any) => {
resolve(res.data)
});
} catch (error) {
reject(error)
}
})
}

View File

@ -10,6 +10,8 @@ const userPageUrl = '/admin/user/page'
const addUserUrl = '/admin/user' const addUserUrl = '/admin/user'
const modifyPwUrl = "/admin/user/modifyPw"
export function getUserInfo() { export function getUserInfo() {
return new Promise(resolve => { return new Promise(resolve => {
getData(userInfoUrl).then((data: any) => { getData(userInfoUrl).then((data: any) => {
@ -46,7 +48,14 @@ export function editPassword(data: any) {
export function userPage(data: any) { export function userPage(data: any) {
return new Promise(resolve => { return new Promise(resolve => {
getData(userPageUrl, data).then((res: any) => { request({
url: userPageUrl,
method: "post",
headers: {
'Content-Type': CommonHeaderEnum.FORM_CONTENT_TYPE
},
data
}).then((res: any) => {
resolve(res.data) resolve(res.data)
}).catch(err => { }).catch(err => {
console.log(err) console.log(err)
@ -63,3 +72,34 @@ export function addUser(data: any) {
}) })
}) })
} }
export function modifyPw(data: any) {
return new Promise((resolve, reject) => {
request({
url: modifyPwUrl,
method: "post",
headers: {
'Content-Type': CommonHeaderEnum.FORM_CONTENT_TYPE
},
data
}).then((res: any) => {
resolve(res.data)
}).catch(error => {
reject(error)
})
})
}
export function updateUI(data: any) {
return new Promise((resolve, reject) => {
request({
url: addUserUrl,
method: "put",
data
}).then((res: any) => {
resolve(res.data)
}).catch(error => {
reject(error)
})
})
}

View File

@ -7,7 +7,7 @@
<script lang='ts' setup> <script lang='ts' setup>
import { onMounted, reactive, ref, toRefs, watch } from 'vue' import { onMounted, reactive, ref, toRefs, watch } from 'vue'
const props = withDefaults(defineProps(), { const props = withDefaults(defineProps<{total: number}>(), {
total: () => 0 total: () => 0
}) })

View File

@ -1,65 +1,77 @@
<template> <template>
<el-dialog v-model="dialogVisible" :title="title" width="50%"> <el-dialog v-model="dialogVisible" :title="title" width="50%">
<el-upload v-model:file-list="fileList" drag accept=".xls, .xlsx" :auto-upload="false" :limit="1"> <el-upload action="#" v-model:file-list="fileList" drag accept=".xls, .xlsx"
<div class="el-upload__text" style="padding: 40px 10px;font-size: 20px;"> :auto-upload="false" :limit="1" :http-request="handleUpload" ref="uploadRef">
将文件拖到此处 <em>点击上传</em> <div class="el-upload__text" style="padding: 40px 10px;font-size: 20px;">
</div> 将文件拖到此处 <em>点击上传</em>
<template #tip> </div>
<div class="el-upload__tip" style="font-size: 16px;"> <template #tip>
仅允许导入xlsxlsx格式文件<span class="main-color" style="cursor: pointer;" <div class="el-upload__tip" style="font-size: 16px;">
@click="downloadTemplate">下载模板</span> 仅允许导入xlsxlsx格式文件<span class="main-color" style="cursor: pointer;"
</div> @click="downloadTemplate">下载模板</span>
</template> </div>
</el-upload> </template>
</el-upload>
<div style="text-align: right;margin-top: 20px;"> <div style="text-align: right;margin-top: 20px;">
<el-button class="f18" @click="dialogVisible = false">取消</el-button> <el-button class="f18" @click="dialogVisible = false">取消</el-button>
<el-button class="f18" type="primary" @click="importData">确认</el-button> <el-button class="f18" type="primary" @click="importData">确认</el-button>
</div> </div>
</el-dialog> </el-dialog>
</template> </template>
<script lang='ts' setup> <script lang='ts' setup>
import { onMounted, reactive, ref, toRefs, watch } from 'vue' import {ref} from 'vue'
import type { UploadProps, UploadUserFile } from 'element-plus' import type {UploadUserFile} from 'element-plus'
import { ElMessage, ElMessageBox } from 'element-plus' import {ElMessage} from 'element-plus'
import {downBlobFile} from "@/utils/file-util";
import {handleHttpUploadUrl} from "@/api/file-upload";
const emit = defineEmits(['success', 'error']) const emit = defineEmits(['success', 'error'])
const props = defineProps({ const props = defineProps({
title: String, title: String,
templateUrl: String, // templateUrl: String, //
importUrl: String, // importUrl: String, //
}) })
const dialogVisible = ref(false) const dialogVisible = ref(false)
const fileList = ref<UploadUserFile[]>([]) const fileList = ref<UploadUserFile[]>([])
const uploadRef = ref()
defineExpose({ defineExpose({
open, open,
close close
}) })
function open() { function open() {
dialogVisible.value = true dialogVisible.value = true
} }
function close() { function close() {
dialogVisible.value = false dialogVisible.value = false
} }
const downloadTemplate = () => { const downloadTemplate = () => {
window.open(props.templateUrl, '_blank') downBlobFile(props.templateUrl, {}, "temp.xlsx")
} }
const importData = () => { const importData = () => {
// console.log(fileList.value) // console.log(fileList.value)
if(fileList.value.length === 0) { if (fileList.value.length === 0) {
ElMessage.warning('请上传符合格式的xls或xlsx文件') ElMessage.warning('请上传符合格式的xls或xlsx文件')
return return
} }
ElMessage.success('上传成功') uploadRef.value.submit()
close() ElMessage.success('上传成功')
emit('success') close()
// emit('error') emit('success')
// emit('error')
}
function handleUpload(options: any) {
handleHttpUploadUrl(options, props.importUrl).then((res: any) => {
console.log(res)
})
} }
</script> </script>

View File

@ -151,7 +151,6 @@ function handleAvatarSuccess(uploadFile: any) {
function handleUpload(options: any) { function handleUpload(options: any) {
handleHttpUpload(options).then((res: any) => { handleHttpUpload(options).then((res: any) => {
console.log(res)
if (res && res.code == 0) { if (res && res.code == 0) {
formData.value.avatar = res.data.url formData.value.avatar = res.data.url
const param = { const param = {

36
src/utils/file-util.ts Normal file
View File

@ -0,0 +1,36 @@
import request from "@/utils/request";
import {ElMessage} from "element-plus";
export function downBlobFile(url: any, query: any, fileName: string) {
return request({
url: url,
method: 'get',
responseType: 'blob',
params: query,
}).then((response) => {
handleBlobFile(response.data, fileName);
});
}
export function handleBlobFile(response: any, fileName: string) {
// 处理返回的文件流
const blob = response;
if (blob && blob.size === 0) {
ElMessage.error('内容为空,无法下载');
return;
}
const link = document.createElement('a');
// 兼容一下 入参不是 File Blob 类型情况
let binaryData = [] as any;
binaryData.push(response);
link.href = window.URL.createObjectURL(new Blob(binaryData));
link.download = fileName;
document.body.appendChild(link);
link.click();
window.setTimeout(function () {
// @ts-ignore
URL.revokeObjectURL(blob);
document.body.removeChild(link);
}, 0);
}

View File

@ -1,6 +1,7 @@
import * as XLSX from "xlsx" import * as XLSX from "xlsx"
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import { dateFormater } from '@/utils/date-util' import { dateFormater } from '@/utils/date-util'
import {downBlobFile} from "@/utils/file-util";
export const tableRemoveRow = (params: any, callback: (res: boolean) => void) => { export const tableRemoveRow = (params: any, callback: (res: boolean) => void) => {
if (!params.data) params.data = [] if (!params.data) params.data = []
@ -44,13 +45,11 @@ export const tableRemoveRow = (params: any, callback: (res: boolean) => void) =>
} }
export const exportData = (fileName: string, data: Array<any>) => { export const exportData = (fileName: string, data: Array<any>) => {
if(data.length < 1) return downBlobFile("/admin/user/export", {
const wb = XLSX.utils.book_new(); deptId: "",
XLSX.utils.book_append_sheet( phone: "",
wb, username: ""
XLSX.utils.json_to_sheet(data) }, "users.xlsx")
)
XLSX.writeFile(wb, fileName + '.xls'); // 导出Excel
} }
/** /**

View File

@ -5,8 +5,8 @@
<span class="label">用户名</span> <span class="label">用户名</span>
<el-input v-model="queryParams.userName" placeholder="请输入用户名"></el-input> <el-input v-model="queryParams.userName" placeholder="请输入用户名"></el-input>
</div> </div>
<el-button type="primary" icon="Search" @click="queryData(queryParams)">查询</el-button> <el-button type="primary" icon="Search" @click="searchData()">查询</el-button>
<el-button icon="Refresh" @click="queryData()">重置</el-button> <el-button icon="Refresh" @click="resetSearch()">重置</el-button>
</div> </div>
<div class="button-part" style="justify-content: space-between;"> <div class="button-part" style="justify-content: space-between;">
<div> <div>
@ -14,7 +14,7 @@
<el-button icon="FirstAidKit" @click="importData">导入</el-button> <el-button icon="FirstAidKit" @click="importData">导入</el-button>
<el-button icon="Delete" @click="removeData()">删除</el-button> <el-button icon="Delete" @click="removeData()">删除</el-button>
</div> </div>
<TableAbility @searchBtn="isSearch = !isSearch" @refreshBtn="queryData()" <TableAbility @searchBtn="isSearch = !isSearch" @refreshBtn="updateData()"
@downloadBtn="exportData('医生数据', tableData)"></TableAbility> @downloadBtn="exportData('医生数据', tableData)"></TableAbility>
</div> </div>
<div class="table-part"> <div class="table-part">
@ -38,18 +38,18 @@
</el-table-column> </el-table-column>
<el-table-column label="锁定" width="120" align="center"> <el-table-column label="锁定" width="120" align="center">
<template #default="scope"> <template #default="scope">
<span @click.stop><el-switch v-model="scope.row.lockFlag" @change="enableChange(scope.row)"/></span> <span><el-switch v-model="scope.row.lockFlag" @click="enableChange(scope.row)"/></span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" align="center"> <el-table-column label="操作" align="center">
<template #default="scope"> <template #default="scope">
<span @click.stop> <span @click.stop>
<el-button link icon="RefreshLeft" @click="resetPassword(scope.row)" <el-button link icon="RefreshLeft" @click="resetPassword(scope.row)"
:disabled="!scope.row.lockFlag">密码</el-button> :disabled="scope.row.lockFlag == 1">密码</el-button>
<el-button link icon="EditPen" @click="editData(scope.row)" <el-button link icon="EditPen" @click="editData(scope.row)"
:disabled="!scope.row.lockFlag">修改</el-button> :disabled="scope.row.lockFlag == 1">修改</el-button>
<el-button link icon="Delete" @click="removeData(scope.row)" <el-button link icon="Delete" @click="removeData(scope.row)"
:disabled="!scope.row.lockFlag">删除</el-button> :disabled="scope.row.lockFlag == 1">删除</el-button>
</span> </span>
</template> </template>
</el-table-column> </el-table-column>
@ -63,17 +63,18 @@
<DoctorForm ref="doctorFormRef" :type="formDialogTitle === '添加' ? 'add' : 'edit'" @close="isFormDialog = false" <DoctorForm ref="doctorFormRef" :type="formDialogTitle === '添加' ? 'add' : 'edit'" @close="isFormDialog = false"
@save="doctorFormSave"/> @save="doctorFormSave"/>
</el-dialog> </el-dialog>
<ImportDialog ref="importDialogRef" title="用户导入" templateUrl="#" importUrl="#"/> <ImportDialog ref="importDialogRef" title="用户导入"
templateUrl="/admin/sys-file/local/file/user.xlsx" importUrl="/admin/user/import"/>
</template> </template>
<script lang='ts' setup> <script lang='ts' setup>
import {onMounted, reactive, ref, toRefs, watch} from 'vue' import {ref} from 'vue'
import {ElMessage, ElMessageBox} from 'element-plus' import {ElMessage, ElMessageBox} from 'element-plus'
import {tableRemoveRow, exportData} from '@/utils/table-util' import {exportData, tableRemoveRow} from '@/utils/table-util'
import CommonPagination from '@/components/common-pagination.vue' import CommonPagination from '@/components/common-pagination.vue'
import DoctorForm from './form/doctor-form.vue' import DoctorForm from './form/doctor-form.vue'
import ImportDialog from '@/components/import-dialog.vue' import ImportDialog from '@/components/import-dialog.vue'
import {userPage} from "@/api/user"; import {modifyPw, updateUserInfo, userPage} from "@/api/user";
const tableRef = ref() const tableRef = ref()
const doctorFormRef = ref() const doctorFormRef = ref()
@ -92,7 +93,16 @@ const total = ref(0)
queryData() queryData()
function queryData(e?: any) { function searchData() {
updateData()
}
function resetSearch() {
queryParams.value.userName = ""
updateData()
}
function queryData() {
loading.value = true loading.value = true
userPage({ userPage({
current, current,
@ -102,15 +112,18 @@ function queryData(e?: any) {
loading.value = false loading.value = false
total.value = res.data.total total.value = res.data.total
tableData.value = res.data.records tableData.value = res.data.records
if (current < total.value) {
current += size
}
console.log(res)
}).catch(error => { }).catch(error => {
loading.value = false loading.value = false
}) })
} }
function updateData() {
current = 0
total.value = 0
tableData.value = []
queryData()
}
const addData = () => { const addData = () => {
isFormDialog.value = true isFormDialog.value = true
formDialogTitle.value = '添加' formDialogTitle.value = '添加'
@ -134,15 +147,33 @@ const removeData = (e?: any) => {
}) })
} }
const enableChange = (e: any) => { const enableChange = (e: any) => {
if (e.lockFlag == 0) { console.log(e)
updateUserInfo({
} else {} username: e.username,
ElMessage.success(e.lockFlag ? '启用成功' : '禁用成功') lockFlag: e.lockFlag ? '1' : '0'
}).then((res: any) => {
if (res.code == 0) {
ElMessage.success(e.lockFlag ? '锁定成功' : '解锁成功')
}
})
} }
const resetPassword = (e: any) => { const resetPassword = (e: any) => {
ElMessageBox.confirm('是否确定要重置密码?', '系统提醒', {type: 'warning', draggable: true}).then(() => { ElMessageBox.prompt('是否确定要重置密码?', '系统提醒', {
ElMessage.success('重置成功!') type: 'warning',
}).catch(() => { draggable: true,
inputPattern: /^(?=.*\d)(?=.*[a-zA-Z])(?=.*[^\da-zA-Z\s]).{9,15}$/,
inputErrorMessage: "密码至少包含字母、数字、特殊字符不少于9位最多15位"
}).then((inputVal) => {
modifyPw({
username: e.username,
password: inputVal.value
}).then((res: any) => {
if (res.code == 0) {
ElMessage.success('重置成功!')
} else {
ElMessage.error(res.msg)
}
})
}) })
} }
const editData = (e: any) => { const editData = (e: any) => {
@ -150,25 +181,24 @@ const editData = (e: any) => {
formDialogTitle.value = '修改' formDialogTitle.value = '修改'
setTimeout(() => { setTimeout(() => {
doctorFormRef.value.resetData() doctorFormRef.value.resetData()
doctorFormRef.value.formData = JSON.parse(JSON.stringify(e)) const val = JSON.parse(JSON.stringify(e));
val.role = []
val.roleList.forEach((role: any) => {
val.role.push(role.roleId)
})
doctorFormRef.value.formData = val
}, 0) }, 0)
} }
const tableRowClick = (row: any) => { const tableRowClick = (row: any) => {
tableRef.value.toggleRowSelection(row) tableRef.value.toggleRowSelection(row)
} }
const doctorFormSave = (data: any, type: string) => { const doctorFormSave = (data: any, type: string) => {
if (type === 'add') { updateData()
tableData.value.unshift(Object.assign({}, data))
} else {
tableData.value.forEach((item: any) => {
if (item.id === data.id) {
Object.assign(item, data)
}
})
}
} }
const paginationChange = (page: number, size: number) => { const paginationChange = (page: number, s: number) => {
console.log(page, size) current = page
size = s
queryData()
} }
</script> </script>

View File

@ -34,16 +34,16 @@
<el-input v-model="formData.phone" placeholder="请输入电话"></el-input> <el-input v-model="formData.phone" placeholder="请输入电话"></el-input>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12" v-if="type != 'edit'">
<el-form-item label="启用" prop="lockFlag"> <el-form-item label="锁定" prop="lockFlag">
<el-radio-group v-model="formData.lockFlag"> <el-radio-group v-model="formData.lockFlag">
<el-radio :label="'0'" border>有效</el-radio> <el-radio :label="'0'" border>解锁</el-radio>
<el-radio :label="'1'" border>禁用</el-radio> <el-radio :label="'1'" border>锁定</el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-row v-if="type === 'edit'"> <el-row v-if="type != 'edit'">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="密码" prop="password"> <el-form-item label="密码" prop="password">
<el-input v-model="formData.password" placeholder="请输入密码" <el-input v-model="formData.password" placeholder="请输入密码"
@ -63,7 +63,7 @@
import {onMounted, reactive, ref, toRefs, watch} from 'vue' import {onMounted, reactive, ref, toRefs, watch} from 'vue'
import {ElMessage, ElMessageBox} from 'element-plus' import {ElMessage, ElMessageBox} from 'element-plus'
import {getRoleList} from "@/api/role"; import {getRoleList} from "@/api/role";
import {addUser} from "@/api/user"; import {addUser, updateUI} from "@/api/user";
const emit = defineEmits(['close', 'save']) const emit = defineEmits(['close', 'save'])
@ -111,10 +111,10 @@ const formData = ref({
id: '', id: '',
username: '', username: '',
name: '', name: '',
role: '', role: [],
email: '', email: '',
phone: '', phone: '',
password: '', password: '',
lockFlag: '0', lockFlag: '0',
} as any) } as any)
@ -128,7 +128,6 @@ getRoleList().then((res: any) => {
} else { } else {
ElMessage.error('角色列表获取失败') ElMessage.error('角色列表获取失败')
} }
console.log(res)
}) })
defineExpose({ defineExpose({
@ -147,10 +146,10 @@ function resetData() {
id: '', id: '',
username: '', username: '',
name: '', name: '',
role: '', role: [],
email: '', email: '',
phone: '', phone: '',
password: '', password: '',
lockFlag: '0', lockFlag: '0',
} }
} }
@ -158,15 +157,34 @@ function resetData() {
const saveData = async () => { const saveData = async () => {
await formRef.value.validate((valid: any, fields: any) => { await formRef.value.validate((valid: any, fields: any) => {
if (valid) { if (valid) {
addUser(formData.value).then((data: any) => { if (props.type == "add") {
console.log(data) addUser(formData.value).then((data: any) => {
}) if (data.code == 0) {
ElMessage.success('保存成功!') ElMessage.success('保存成功!')
emit('save', formData.value, props.type) emit('save', formData.value, props.type)
console.log(formData.value) close()
close() } else {
} else { ElMessage.error("保存失败")
// console.log('error submit!', fields) }
})
} else {
updateUI({
userId: formData.value.userId,
username: formData.value.username,
name: formData.value.name,
role: formData.value.role,
email: formData.value.email,
phone: formData.value.phone
}).then((data: any) => {
if (data.code == 0) {
ElMessage.success('修改成功!')
emit('save', formData.value, props.type)
close()
} else {
ElMessage.error("修改失败")
}
})
}
} }
}) })
} }

View File

@ -24,14 +24,14 @@ export default defineConfig({
proxy: { proxy: {
'/api': { '/api': {
//target: 'http://192.168.137.235:9999', // 目标服务器地址 //target: 'http://192.168.137.235:9999', // 目标服务器地址
target: 'http://localhost:8888', // 目标服务器地址 target: 'http://localhost:9999', // 目标服务器地址
ws: true, // 是否启用 WebSocket ws: true, // 是否启用 WebSocket
changeOrigin: true, // 是否修改请求头中的 Origin 字段 changeOrigin: true, // 是否修改请求头中的 Origin 字段
rewrite: (path) => path.replace(/^\/api/, ''), rewrite: (path) => path.replace(/^\/api/, ''),
}, },
'/socket.io': { '/socket.io': {
//target: 'ws://192.168.137.235:9999', //target: 'ws://192.168.137.235:9999',
target: 'ws://localhost:8888', target: 'ws://localhost:9999',
ws: true, ws: true,
changeOrigin: true, changeOrigin: true,
rewrite: (path) => path.replace(/^\/socket.io/, ''), rewrite: (path) => path.replace(/^\/socket.io/, ''),