feat(address-book): 添加通讯录导入导出功能

This commit is contained in:
dj
2024-12-07 21:32:12 +08:00
parent b0009057db
commit f4b0199ef8
4 changed files with 208 additions and 34 deletions

2
components.d.ts vendored
View File

@@ -52,6 +52,7 @@ declare module '@vue/runtime-core' {
ElTooltip: typeof import('element-plus/es')['ElTooltip']
ElTree: typeof import('element-plus/es')['ElTree']
ElTreeSelect: typeof import('element-plus/es')['ElTreeSelect']
ElUpload: typeof import('element-plus/es')['ElUpload']
FvCheckbox: typeof import('./src/fvcomponents/fvCheckbox/index.vue')['default']
FvForm: typeof import('./src/fvcomponents/fvForm/index.vue')['default']
FvFormDialog: typeof import('./src/fvcomponents/fvFormDialog/index.vue')['default']
@@ -68,6 +69,7 @@ declare module '@vue/runtime-core' {
IconSelect: typeof import('./src/components/iconSelect/index.vue')['default']
IconSupport: typeof import('./src/components/icons/IconSupport.vue')['default']
IconTooling: typeof import('./src/components/icons/IconTooling.vue')['default']
ImportExcel: typeof import('./src/components/ImportExcel.vue')['default']
InfoLiveCall: typeof import('./src/components/infoLiveCall/index.vue')['default']
LiveCall: typeof import('./src/components/liveCall/index.vue')['default']
LiveCallItem: typeof import('./src/components/liveCall/LiveCallItem.vue')['default']

View File

@@ -1,4 +1,6 @@
import request from '@/utils/request.js'
import axios from "axios";
import {getToken} from "@/utils/auth";
export const addContact = (data) => {
return request({
@@ -28,3 +30,23 @@ export const deleteContact = (contactIds) => {
method: 'delete'
})
}
export const importContact = (data) => {
return request({
url: '/contact/import',
method: 'post',
data
})
}
export const exportContact = (data) => {
return axios.post(
`${import.meta.env.VITE_BASE_URL}/contact/export`,data,
{
responseType: 'blob',
headers: {
Authorization: getToken()
}
}
);
}

View File

@@ -0,0 +1,105 @@
<template>
<el-upload :file-list="[]"
:limit="maxSize"
with-credentials
:multiple="multiple"
:http-request="httpRequestHandle"
:data="uploadParams"
:auto-upload="true"
:show-file-list="false"
:before-upload="beforeUpload"
:on-remove="handleRemove"
>
<el-button color="#DED0B2" style="margin-left: 10px; margin-right: 10px;" :loading="loading" v-perm="['order:contacts:import']" :disabled="disabled">导入</el-button>
</el-upload>
</template>
<script setup>
import {ElMessageBox, ElNotification} from "element-plus";
import {getToken} from '@/utils/auth'
import axios from "axios";
const props = defineProps({
value: {
type: Array,
default: () => {
return []
}
},
maxSize: {
type: Number,
default: 30
},
disabled: {
type: Boolean,
default: false
},
multiple: {
type: Boolean,
default: false
},
})
const loading = ref(false)
const baseURL = import.meta.env.VITE_BASE_URL
const uploadFileUrl = ref(baseURL + "/contact/import")
const headers = reactive({
authorization: getToken()
})
const uploadParams = ref({})
const emit = defineEmits(["input", "getFile", "delete"])
const handleRemove = (file) => {
emit("delete", file.response.data.id)
}
const beforeUpload = () => {
loading.value = true
return true
}
const httpRequestHandle = (param) => {
// loading.value=true
let file = param.file
axios.post(uploadFileUrl.value, {
file: file
}, {
headers: {
'Content-Type': 'multipart/form-data',
...headers
}
}).then(res => {
loading.value=false
handleUploadSuccess(res)
}).catch(error => {
loading.value=false
uploadError(error)
})
}
const handleUploadSuccess = (res) => {
let data = res.data
ElNotification({
title: '提示',
message: data.code === 1000 ? '导入成功' : '导入失败',
type: data.code === 1000 ? 'success' : 'error'
})
emit("success")
}
const uploadError = (error) => {
loading.value = false
ElNotification({
title: '提示',
message: "导入失败,请稍后再试!",
type: 'error'
})
}
defineExpose({
handleRemove
})
</script>
<style lang="scss" scoped>
a {
font-size: 14px;
color: #2a99ff;
}
</style>

View File

@@ -1,19 +1,27 @@
<template>
<div class="address-book">
<fvSearchForm :searchConfig="searchConfig" @search="searchAddressBook"></fvSearchForm>
<fvTable ref="tableIns" :tableConfig="addressBookTableConfig" @headBtnClick="headBtnClick"
@selectionChange="selectionChange"></fvTable>
<fvFormDialog ref="formDialogRef" :title="dialogTitle" :dialogType="dialogType"
:form-schema="formSchema" :form-rules="formRules"
@dialogSubmit="handleSubmitAddressBook"></fvFormDialog>
</div>
<div style="display: flex;">
<el-button type="primary" v-perm="auths.add" @click="handleAdd">新增</el-button>
<import-excel @success="importAddress"/>
<el-button type="info" v-perm="auths.export" @click="handleExport">导出</el-button>
<el-button type="danger" v-perm="auths.delete" @click="handleMoreDelete">删除</el-button>
</div>
<!-- @headBtnClick="headBtnClick"-->
<fvTable ref="tableIns" :tableConfig="addressBookTableConfig"
@selectionChange="selectionChange"></fvTable>
<fvFormDialog ref="formDialogRef" :title="dialogTitle" :dialogType="dialogType"
:form-schema="formSchema" :form-rules="formRules"
@dialogSubmit="handleSubmitAddressBook"></fvFormDialog>
</div>
</template>
<script setup lang="jsx">
import fvSelect from '@/fvcomponents/fvSelect/index.vue'
import {addContact, editContact, getContactDetail, deleteContact} from "@/api/address-book";
import {addContact, editContact, getContactDetail, deleteContact, exportContact} from "@/api/address-book";
import {ElMessage, ElMessageBox} from "element-plus";
import {reactive} from "vue";
import ImportExcel from "@/components/ImportExcel.vue";
const router = useRouter()
const tableIns = ref()
@@ -50,8 +58,8 @@ const formRules = reactive({
{required: true, message: "请输入姓名", trigger: ["change", "blur"]}
],
phone: [
{required: true, message: "请输入手机号码", trigger: ["change", "blur"]},
{ validator: checkPhone, trigger: ["change", "blur"]},
{required: true, message: "请输入手机号码", trigger: ["change", "blur"]},
{validator: checkPhone, trigger: ["change", "blur"]},
]
});
const formSchema = computed(() => {
@@ -128,7 +136,7 @@ const formSchema = computed(() => {
props: {
placeholder: '请输入手机号',
clearable: true,
controls:false
controls: false
},
},
{
@@ -181,6 +189,8 @@ const searchConfig = reactive([
const auths = reactive({
add: ['order:contacts:add'],
edit: ['order:contacts:edit'],
import: ['order:contacts:import'],
export: ['order:contacts:export'],
delete: ['order:contacts:del'],
})
const addressBookTableConfig = reactive({
@@ -248,8 +258,8 @@ const addressBookTableConfig = reactive({
showOverflowTooltip: false,
currentRender: ({row, index}) => {
let btn = []
btn.push({label: '编辑', prem: auths.edit, func: () => handleEdit(row), type: 'primary'})
btn.push({label: '删除', prem: auths.delete,func: () => handleSingleDelete(row), type: 'danger'})
btn.push({label: '编辑', prem: auths.edit, func: () => handleEdit(row), type: 'primary'})
btn.push({label: '删除', prem: auths.delete, func: () => handleSingleDelete(row), type: 'danger'})
return (
<div style={{width: '100%'}}>
{
@@ -272,8 +282,10 @@ const addressBookTableConfig = reactive({
api: '/contact/list',
params: {},
btns: [
{name: '新增', key: 'add', type: 'primary' , auth: auths.add},
{name: '删除', key: 'delete', type: 'danger', auth: auths.delete},
// {name: '新增', key: 'add', type: 'primary', auth: auths.add},
// {name: '导入', key: 'import', type: 'warning', auth: auths.import},
// {name: '导出', key: 'export', type: 'info', auth: auths.export},
// {name: '删除', key: 'delete', type: 'danger', auth: auths.delete},
]
})
const searchAddressBook = (val) => {
@@ -286,18 +298,50 @@ const searchAddressBook = (val) => {
addressBookTableConfig.params = obj
tableIns.value.refresh()
}
const importAddress = () => {
tableIns.value.refresh()
}
const headBtnClick = (key) => {
switch (key) {
case 'add':
handleAdd()
break;
case 'import':
handleImport()
break;
case 'export':
handleExport()
break;
case 'delete':
handleMoreDelete()
break;
}
}
//通讯录导入
const handleImport = () => {
}
//通讯录导出
const handleExport = () => {
exportContact().then(res => {
let link = document.createElement('a')
try {
let blob = new Blob([res.data], {type: 'application/vnd.ms-excel'});
let _fileName = "运维智能语音服务系统-通讯录.xlsx"
link.style.display = 'none';
// 兼容不同浏览器的URL对象
const url = window.URL || window.webkitURL || window.moxURL;
link.href = url.createObjectURL(blob);
link.setAttribute('download', _fileName.substring(_fileName.lastIndexOf('_') + 1))
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
url.revokeObjectURL(link.href);//销毁url对象
} catch (e) {
console.log('下载的文件出错', e)
}
})
}
const handleAdd = () => {
formDialogRef.value.openOrCloseDialog(true)
dialogTitle.value = "新增通讯录";
@@ -333,7 +377,7 @@ const selectionChange = (selection) => {
if (selection.length !== 0) {
contactIds.value = selection.map(item => item.contactsId).join()
} else {
contactIds.value=''
contactIds.value = ''
}
}
const deleteContactMethod = (contactsId) => {
@@ -347,17 +391,17 @@ const deleteContactMethod = (contactsId) => {
})
}
const handleMoreDelete = () => {
if(contactIds.value){
ElMessageBox.confirm(`确认删除选择的通讯录吗?`, '系统提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
if (contactIds.value) {
ElMessageBox.confirm(`确认删除选择的通讯录吗?`, '系统提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
deleteContactMethod(contactIds.value)
})
}else{
ElMessage.warning("请选择要删除的通讯录")
}
})
} else {
ElMessage.warning("请选择要删除的通讯录")
}
}
const handleSingleDelete = (row) => {
ElMessageBox.confirm(`确认删除姓名为${row.name}的通讯录吗?`, '系统提示', {
@@ -374,13 +418,13 @@ const handleSubmitAddressBook = async (formInstance) => {
if (!formInstance) return;
let validate = await formInstance.validate()
if (!validate.isValidate) return;
if(formInstance.getValues().role=='0'&&!formInstance.getValues().team){
ElMessage.warning('请输入班组信息');
return;
if (formInstance.getValues().role == '0' && !formInstance.getValues().team) {
ElMessage.warning('请输入班组信息');
return;
}
if(formInstance.getValues().role=='1'&&!formInstance.getValues().dispatchUnit){
ElMessage.warning('请输入拨打单位');
return;
if (formInstance.getValues().role == '1' && !formInstance.getValues().dispatchUnit) {
ElMessage.warning('请输入拨打单位');
return;
}
if (dialogType.value === "add") {
@@ -407,11 +451,12 @@ const handleSubmitAddressBook = async (formInstance) => {
}
</script>
<style lang="scss">
.address-book{
.address-book {
.el-input-number {
width: 100% !important;
.el-input__inner{
.el-input__inner {
text-align: left;
}
}