Commit d2c4018b authored by kang.nie@inzymeits.com's avatar kang.nie@inzymeits.com
Browse files

初始化代码

parent de8a8ae5
Pipeline #3105 failed with stages
in 0 seconds
<template>
<div class="login-container">
<div class="login-form-container">
<img v-if="logo" class="login-decoration-logo" :src="logo">
<!-- <div class="login-decoration-slogan">做国际一流的汽车数字化运营服务提供商,共建设美好车生活</div> -->
<div class="login-form-wrap">
<!-- 登录 -->
<LoginTab
v-if="status === 'login'"
@forgetPassword="forgetPassword"/>
</div>
<div class="login-version">Copyright 2017-2019 联通智网科技股份有限公司 版权所有 京ICP备16005440号-1</div>
</div>
</div>
</template>
<script>
import LoginTab from './components/LoginTab'
export default {
name: 'Login',
components: { LoginTab },
data() {
return {
logo: this.$store.getters.logo,
companyName: this.$store.getters.companyName,
status: 'login',
isTablet: window.OS.isTablet
}
},
watch: {
},
mounted() {
},
methods: {
forgetPassword() {
this.$router.push({ name: 'ResetPassword' })
}
}
}
</script>
<style lang="scss">
.login-container {
background-image: url(../../assets/img/login-bg.jpeg);
background-size: 100% 100%;
background-repeat: no-repeat;
min-height: 100%;
width: 100%;
overflow: hidden;
.login-form-container {
background-image: url(../../assets/img/login-decoration.svg);
background-repeat: no-repeat;
background-size: 520px auto;
background-position: right 770px center;
padding: 70px;
width: 100%;
height: 100vh;
position: relative;
margin: 0 auto;
max-width: 1400px;
.login-decoration-logo {
width: auto;
height: 42px;
}
.login-decoration-slogan {
color: rgba(0, 0, 0, 0.6);
font-size: 14px;
font-weight: 400;
margin-top: 12px;
}
.login-version {
bottom: 40px;
color: #758092;
opacity: 0.5;
font-size: 14px;
text-align: center;
font-weight: 400;
position: absolute;
left: 0px;
right: 0px;
}
}
.login-form-wrap {
background: #FFFFFF;
box-shadow: 0 6px 27px 0 rgba(37,48,68,0.08);
border-radius: 8px;
width: 426px;
min-height: 432px;
padding: 36px 70px 0;
position: absolute;
top: 50%;
right: 190px;
transform: translateY(-50%);
.el-form-item {
align-items: flex-end;
display: flex;
margin-bottom: 0px;
height: 66px;
.el-form-item__content {
width: 100%;
}
.el-input__inner {
box-shadow: none !important;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
border-top-width: 0;
border-left-width: 0;
border-right-width: 0;
border-bottom-width: 1px;
color: #393939;
padding-left: 2px;
}
}
}
}
</style>
<template>
<div class="reset-password ">
<div class="reset-password-container" :style="{ width: isTablet ? '100%' : '1400px' }">
<img v-if="logo" :src="logo" class="reset-decoration-logo">
<div class="reset-form-wrapper">
<div v-if="result === ''">
<div class="title">忘记密码</div>
<MsgValidate ref="msgValidateRef">
<template #password>
<el-form ref="formRef" :model="resetForm" :rules="resetRules">
<el-form-item prop="password" style="height:104px">
<el-input v-model="resetForm.password" type="password" placeholder="请输入新密码"/>
<div class="tips">密码长度必须为8~20位字符,由大写字母、小写字母、数字、特殊符号中的3种及以上类型组成</div>
</el-form-item>
<el-form-item prop="rePassword">
<el-input v-model="resetForm.rePassword" type="password" placeholder="请输入确认密码"/>
</el-form-item>
</el-form>
</template>
</MsgValidate>
<!-- <el-form ref="formRef" :model="resetForm" :rules="resetRules" label-position="top">
<el-row :gutter="40">
<el-col>
<div class="head">
<div class="title">找回密码</div>
<el-button type="text" @click="toLogin">直接登录</el-button>
</div>
</el-col>
<el-col :span="12">
<el-form-item prop="phone" label="手机号码">
<el-input v-model="resetForm.phone" placeholder="请输入手机号码" maxlength="11" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="图形验证码" prop="captcha">
<div class="flex">
<el-input v-model="resetForm.captcha" maxlength="6" placeholder="请输入图形验证码"/>
<img :src="captchaImg" class="captch-img" alt="验证码" @click="fetchVerifyGraphic">
</div>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="验证码" prop="smsCode">
<div class="flex">
<el-input v-model="resetForm.smsCode" maxlength="6" placeholder="请输入验证码"/>
<el-button :disabled="time > 0" type="primary" @click="getSmsCaptcha" class="sms-btn">{{ captchaBtnText }}</el-button>
</div>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="40">
<el-col>
<div class="head" style="margin-top: 30px">
<div class="title">重置密码</div>
</div>
</el-col>
<el-col :span="12">
<el-form-item label="新密码" prop="password">
<el-input v-model="resetForm.password" type="password" placeholder="请输入新密码" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="确认密码" prop="rePassword">
<el-input v-model="resetForm.rePassword" type="password" placeholder="请输入确认密码"/>
</el-form-item>
</el-col>
</el-row>
</el-form> -->
<el-button :loading="loading" type="primary" class="btn-reset" @click.native.prevent="reset">完成</el-button>
<div><el-button type="text" @click="toLogin">去登录</el-button></div>
</div>
<ResetResult :result="result" v-if="result !== ''" />
</div>
<div class="version">Copyright 2017-2019 联通智网科技股份有限公司 版权所有 京ICP备16005440号-1</div>
</div>
</div>
</template>
<script>
// import { validPhone } from '@/utils/validate'
import { forgetPassword, getLoginSecretKey } from '@/api/user'
import ResetResult from './components/ResetResult.vue'
import { getJMJqueryParams } from '@/utils/sm4'
import MsgValidate from './components/MsgValidate.vue'
export default {
name: 'ResetPassword',
components: { ResetResult, MsgValidate },
data() {
// const validateUsername = (rule, value, callback) => {
// if (!validPhone(value)) {
// callback(new Error('请输入手机号码'))
// } else {
// callback()
// }
// }
// const validatePassword = (rule, value, callback) => {
// if (value.length < 6) {
// callback(new Error('请输入短信验证码'))
// } else {
// callback()
// }
// }
// const validateCaptcha = (rule, value, callback) => {
// if (value.length !== 4) {
// callback(new Error('请输入验证码'))
// } else {
// callback()
// }
// }
const validateRePassword = (rule, value, callback) => {
if (value !== this.resetForm.password) {
callback(new Error('两次密码输入不一致'))
} else {
callback()
}
}
return {
logo: this.$store.getters.logo,
companyName: this.$store.getters.companyName,
resetForm: {
// phone: '',
// captcha: '',
// smsCode: '',
password: '',
rePassword: '',
requestId: '',
platformSource: 'Web'
},
resetRules: {
// phone: [
// { required: true, message: '请输入手机号', trigger: 'blur' },
// { trigger: 'blur', validator: validateUsername }
// ],
// captcha: [
// { required: true, message: '请输入图形验证码', trigger: 'blur' },
// { trigger: 'blur', validator: validateCaptcha }
// ],
// smsCode: [
// { required: true, message: '请输入验证码', trigger: 'blur' },
// { trigger: 'blur', validator: validatePassword }
// ],
password: [
{ required: true, message: '请输入密码', trigger: 'blur' }
],
rePassword: [
{ required: true, message: '请输入确认密码', trigger: 'blur' },
{ trigger: 'blur', validator: validateRePassword }
]
},
// 图片验证码
// captchaImg: '',
// // 请求图片验证码返回的请求id
// requestId: '',
// captchaBtnText: '发送验证码',
// timer: null,
// time: 0,
loading: false,
result: '',
isTablet: window.OS.isTablet
}
},
watch: {
$route: {
handler: function(route) {
this.redirect = route.query && route.query.redirect
},
immediate: true
}
},
mounted() {
// 默认查询图片验证码
// this.fetchVerifyGraphic()
},
methods: {
/**
* 查询图片验证码
*/
// async fetchVerifyGraphic() {
// // 获取图片验证码
// const { captchaImg, requestId } = await getGraphic({ platformSource: 'Web' })
// // 记录当前图片验证码
// this.captchaImg = captchaImg
// // 请求id
// this.requestId = requestId
// },
/**
* 获取短信验证码
*/
// getSmsCaptcha() {
// // 校验结果
// const validResult = []
// this.$refs.formRef.validateField(
// ['phone', 'captcha'],
// (errorMsg) => {
// if (!errorMsg) {
// validResult.push(errorMsg)
// // 没有校验完全
// if (validResult.length !== 2) {
// return
// }
// clearTimeout(this.timer)
// sendSmsCaptcha({
// phone: this.resetForm.phone,
// captchaImage: this.resetForm.captcha,
// requestId: this.requestId,
// platformSource: 'Web',
// tenantNo: this.$route.query.tenantNo
// }).then(data => {
// this.time = 60
// this.captchaBtnText = `${this.time - 1}S后重发`
// this.countdown()
// }).catch(() => {
// // 如果接口报错了,则刷新二维码
// this.fetchVerifyGraphic()
// this.captchaBtnText = '重新获取'
// })
// }
// })
// },
/**
* 开始倒计时
*/
// countdown() {
// this.timer = setTimeout(() => {
// if (this.time > 1) {
// this.time--
// this.captchaBtnText = `${this.time}S后重发`
// this.countdown()
// } else {
// this.time = 0
// clearTimeout(this.timer)
// this.captchaBtnText = '重新获取'
// }
// }, 1000)
// },
// 找回密码 下一步
reset() {
// 获取
const msgParams = this.$refs.msgValidateRef.getData()
this.$refs.formRef.validate(async valid => {
if (valid) {
if (!msgParams) return
const params = { ...this.resetForm, ...msgParams, ...{ smsCode: msgParams.sms }}// cloneDeep(this.resetForm)
console.log(params, 'params')
delete params.rePassword
delete params.captcha
delete params.sms
this.loading = true
await this.getSecretKey(params)
forgetPassword(params)
.then(() => {
this.loading = false
this.result = 'success'
})
.catch((error) => {
// 连接似乎有问题,请检查网络
if (error.code === 0) return (this.result = 'NetworkError')
// 失败,清空验证码们,并重新获取图形验证码
this.$refs.msgValidateRef.clearInit()
this.$message.error({ message: error.message, type: 'error', duration: 5 * 1000 })
this.loading = false
})
} else {
return false
}
})
},
// 获取随机请求id-登录密码加密
async getSecretKey(params) {
try {
const { requestId, secretKey } = await getLoginSecretKey()
params.requestId = requestId
params.password = getJMJqueryParams(params.password, secretKey)
} catch (error) {
// 连接似乎有问题,请检查网络
error.code === 0 && (this.result = 'NetworkError')
}
},
toLogin() {
this.$router.push({ name: 'Login' })
}
}
}
</script>
<style lang="scss">
.reset-password {
background-image: url(../../assets/img/login-bg.jpeg);
background-size: 100% 100%;
background-repeat: no-repeat;
min-height: 100%;
width: 100%;
overflow: hidden;
.reset-password-container {
background-repeat: no-repeat;
background-size: 520px auto;
background-position: right 770px center;
padding: 70px;
width: 1400px;
height: 100vh;
position: relative;
margin: 0 auto;
.reset-decoration-logo {
background-image: url(../../assets/img/login-logo.svg);
background-size: 100% 100%;
width: auto;
height: 42px;
}
.reset-form-wrapper {
width: 426px;
min-height: 585px;
background: #FFFFFF;
box-shadow: 0px 6px 27px 0px rgba(37, 48, 68, 0.08);
border-radius: 8px;
padding: 32px 70px;
position: absolute;
top: 50%;
left: 50%;
transform: translateX(-50%) translateY(-50%);
text-align: center;
.head {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
height: 46px;
padding-bottom: 24px;
border-bottom: 1px dashed #EBEEF2;
.title {
font-size: 20px;
font-weight: 600;
color: #212026;
line-height: 28px;
}
.to-login {
font-size: 15px;
font-weight: 400;
color: #2A68FF;
line-height: 22px;
}
}
.captch-img {
flex-shrink: 0;
width: 90px;
height: 32px;
margin-left: 8px;
cursor: pointer;
}
.sms-btn {
width: 106px;
height: 38px;
margin-left: 8px;
}
.tips {
font-size: 12px;
font-weight: 400;
color: #71747B;
line-height: 17px;
text-align: left;
margin-top: 4px;
}
.btn-reset {
display: block;
background: #3269FF;
border-radius: 4px;
font-size: 16px;
width: 286px;
height: 44px;
margin: 26px auto 0;
}
}
.el-form-item {
align-items: flex-end;
display: flex;
margin-bottom: 0px;
height: 66px;
.el-form-item__content {
width: 100%;
}
.el-input__inner {
box-shadow: none !important;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
border-top-width: 0;
border-left-width: 0;
border-right-width: 0;
border-bottom-width: 1px;
color: #393939;
padding-left: 2px;
}
}
.version {
bottom: 40px;
color: #758092;
opacity: 0.5;
font-size: 14px;
text-align: center;
font-weight: 400;
position: absolute;
left: 0px;
right: 0px;
}
.flex {
display: flex;
flex-direction: row;
justify-content: flex-start;
}
}
}
</style>
<template>
<div class="user-operation">
<el-dialog
:visible="visible"
:title="`${type === 'add' ? '新增' : '修改'}账户`"
:close-on-click-modal="false"
:close-on-press-escape="false"
class="rnr-dialog"
width="960px"
@close="$emit('update:visible', false)"
>
<el-form ref="formRef" :model="data" label-position="top">
<el-row :gutter="24">
<el-col :span="12">
<el-form-item :rules="IS_NOT_EMPTY('请输入姓名')" prop="userName" label="姓名">
<el-input v-model="data.userName" placeholder="请输入姓名" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item :rules="IS_NOT_EMPTY('请输入昵称')" prop="nickName" label="昵称">
<el-input v-model="data.nickName" placeholder="请输入昵称" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item :rules="[IS_NOT_EMPTY('请输入手机号'), IS_PHONE()]" prop="phone" label="手机号">
<el-input v-model="data.phone" type="number" placeholder="请输入手机号" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item :rules="IS_NOT_EMPTY('请输入用户名')" prop="account" label="用户名">
<el-input v-model="data.account" placeholder="请输入用户名" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24" v-if="type === 'add'">
<el-col :span="12">
<el-form-item :rules="[IS_NOT_EMPTY('请输入密码'), IS_RIGHT_PASSWORD()]" prop="password" label="密码">
<el-input v-model="data.password" :placeholder="type === 'add' ? '请确认输入的密码' : '******'" type="password" />
<div class="el-form-item__field-tip">密码长度必须为8~20位字符,由大写字母、小写字母、数字、特殊符号中的3种及以上类型组成</div>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item :rules="[IS_NOT_EMPTY('请输入确认密码'), CONFIRM_PASSWORD]" prop="confirmPassword" label="确认密码">
<el-input v-model="data.confirmPassword" :placeholder="type === 'add' ? '请确认输入的密码' : '******'" type="password"/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item :rules="IS_NOT_EMPTY('请选择角色', 'change')" prop="roleCode" label="角色">
<el-select v-model="data.roleCode" placeholder="请选择角色">
<el-option v-for="role in roleList" :key="role.value" v-bind="role" />
</el-select>
</el-form-item>
</el-col>
</el-row>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="handleClose">取消</el-button>
<el-button :loading="isLoading" type="primary" @click="handleSubmit">保存</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import { queryRoListByOrganId, addUserEnterpriseAccount, updateUserEnterpriseAccount } from '@/api/management'
import { IS_NOT_EMPTY, IS_PHONE, CONFIRM_PASSWORD, IS_RIGHT_PASSWORD } from '../../rules'
import '../../dealer/dialog.scss'
export default {
props: {
visible: {
type: Boolean,
default: false
},
type: {
type: String,
default: 'add'
},
data: {
type: Object,
default: () => {}
}
},
data() {
return {
IS_NOT_EMPTY,
IS_PHONE,
IS_RIGHT_PASSWORD,
isLoading: false,
roleList: []
}
},
computed: {
/**
* 确认密码
*/
CONFIRM_PASSWORD() {
return CONFIRM_PASSWORD(this.data.password)
}
},
watch: {
// 如果处于可见状态
visible() {
if (this.visible) {
// 角色名称
const { roleName } = this.data || {}
// 处理数据
this.roleList.forEach(role => {
// 如果当前角色名称能匹配上
if (roleName === role.label) {
this.data.roleCode = role.value
}
})
this.$nextTick(() => {
this.$refs.formRef.clearValidate()
})
}
}
},
mounted() {
this.queryRoListByOrganId()
},
methods: {
/**
* 通过组织id查询角色列表
*/
async queryRoListByOrganId() {
// 组织id
const { organId } = this.$store.getters
// 开始获取组织列表
const list = await queryRoListByOrganId({
organId: this.$route.query.organId || organId
})
this.roleList = list.map(role => {
return {
label: role.roleName,
value: role.roleCode
}
})
},
/**
* 点击关闭方法
*/
handleClose() {
this.$emit('update:visible', false)
},
/**
* 点击提交方法
*/
handleSubmit() {
// 开始校验用户输入
this.$refs.formRef.validate(async valid => {
// 如果校验不成功
if (!valid) {
return
}
// 按钮出现loading状态
this.isLoading = true
try {
// 如果当前需要新增
if (this.type === 'add') {
await addUserEnterpriseAccount(this.data)
}
// 如果当前需要修改
if (this.type === 'edit') {
await updateUserEnterpriseAccount(this.data)
}
// 关闭弹框
this.handleClose()
// 开始刷新页面
this.$emit('refresh')
} catch (error) {
console.error(error)
}
// 关闭loading状态
this.isLoading = false
})
}
}
}
</script>
<template>
<div v-loading.fullscreen.lock="fullscreenLoading" element-loading-spinner="page-loading" class="page-management-account">
<SearchTable
ref="searchTableRef"
v-model="formData"
title="账户管理"
@reset="handleReset"
@submit="handleSubmit"
>
<template slot="slot-form">
<el-col :span="isTablet ? 12 : 6" class="mb-16">
<el-form-item label="组织名称" label-width="68px">
<el-input :value="organName" disabled />
</el-form-item>
</el-col>
<el-col :span="isTablet ? 12 : 6" class="mb-16">
<el-form-item label="用户姓名" label-width="68px">
<el-input v-model="formData.username" placeholder="请输入用户姓名" />
</el-form-item>
</el-col>
<el-col :span="isTablet ? 12 : 6" class="mb-16">
<el-form-item label="用户名" label-width="68px">
<el-input v-model="formData.account" placeholder="请输入用户名" />
</el-form-item>
</el-col>
</template>
<template slot="slot-action-bar">
<el-button type="primary" icon="el-icon-plus" @click="handleOpenUpdateAccountDialog('add')">新增账户</el-button>
</template>
<template slot="slot-table">
<el-table-column prop="userName" label="用户姓名" min-width="120px" />
<el-table-column prop="account" label="用户名" min-width="120px" />
<el-table-column prop="phone" label="手机号" min-width="140px" />
<el-table-column prop="roleName" label="角色" min-width="120px" />
<el-table-column prop="createTime" label="创建时间" sortable width="180px" />
<el-table-column label="用户状态" min-width="120px">
<template slot-scope="scope">
<div class="status-wrap">
<i :class="scope.row.status == 0 ? 'red' : 'green'" class="status-point" />
{{ ['未启用', '已启用'][scope.row.status] }}
</div>
</template>
</el-table-column>
<el-table-column label="操作" width="106px" fixed="right" min-width="100px">
<template slot-scope="scope">
<!-- <el-button v-if="scope.row.status === 0" type="text" @click="handleUnFreeze(scope.row)">启用</el-button>
<el-button v-else type="text" @click="handleFreeze(scope.row)">禁用</el-button>
<span class="separator" /> -->
<el-button type="text" @click="handleOpenUpdateAccountDialog('edit', scope.row)">编辑</el-button>
</template>
</el-table-column>
</template>
</SearchTable>
<!-- 操作用户弹窗 start -->
<UpdateAccount :visible.sync="updateAccountDialog.show" :type="updateAccountDialog.type" :data="updateAccountDialog.data" @refresh="handleRefresh" />
<!-- 操作用户弹窗 end -->
</div>
</template>
<script>
import SearchTable from '@/components/SearchTable'
import UpdateAccount from './components/UpdateAccount.vue'
import { queryUserEnterpriseAccount, unfreezeUserEnterpriseAccount, frozenUserEnterpriseAccount } from '@/api/management'
export default {
name: 'BaseManagement',
components: { SearchTable, UpdateAccount },
data() {
const { organName } = this.$store.getters
return {
organName: this.$route.query.organName || organName,
fullscreenLoading: false,
formData: {
username: '',
account: ''
},
// 更新账户弹框
updateAccountDialog: {
show: false,
type: 'add',
data: {}
},
isTablet: window.OS.isTablet
}
},
methods: {
/**
* 执行提交方法
* @param formData 接口请求数据
* @param callback 回调方法
*/
async handleSubmit(formData, callback) {
// 组织id
const { organId } = this.$store.getters
// 查询接口
const { list, totalCount } = await queryUserEnterpriseAccount({
organId,
...this.$route.query,
...formData
})
// 执行回调
callback({ list, totalCount })
},
/**
* 刷新表格数据
*/
handleRefresh() {
// 重新刷新页面
this.$refs.searchTableRef.handleSubmit()
},
/**
* 打开编辑账户弹框
* @param type 打开弹框类型
* @param row 当前行数据
*/
handleOpenUpdateAccountDialog(type = 'add', row = {}) {
// 优先取当前路由中的组织id
const { organId } = this.$route.query
// 新增、编辑账户弹框
this.updateAccountDialog = {
show: true,
type,
data: { roleCode: '', organId, ...row }
}
},
/**
* 经销商-启用
* @param row 当前行数据
*/
async handleUnFreeze(row) {
// 开始请求接口数据
await unfreezeUserEnterpriseAccount({ uuid: row.uuid })
// 刷新页面数据
this.handleRefresh()
},
/**
* 经销商-禁用
* @param row 当前行数据
*/
async handleFreeze(row) {
// 开始请求接口数据
await frozenUserEnterpriseAccount({ uuid: row.uuid })
// 刷新页面数据
this.handleRefresh()
},
/**
* 点击重置
*/
handleReset() {
// 清空数据
this.formData.username = ''
this.formData.account = ''
// 刷新页面数据
this.handleRefresh()
}
}
}
</script>
<style lang="scss">
.page-management-account {
.mb-16 {
margin-bottom: 16px;
}
.status-wrap {
align-items: center;
display: flex;
.status-point {
border-radius: 3px;
display: inline-block;
width: 6px;
height: 6px;
margin-right: 8px;
&.green {
background-color: #25C343;
}
&.red {
background-color: #FF4D4F;
}
}
}
.separator {
background: #DCDFE6;
display: inline-block;
width: 1px;
height: 14px;
margin: 0 2px -2px;
}
}
</style>
<template>
<div class="word-uploader">
<div class="el-upload">
<img v-if="value.uuid" :src="value.url" class="imageicon" @click="handleOpenViewer">
<div v-else :class="imageIcon" class="imageicon" />
<div v-if="value.uuid" class="file-name">{{ value.name }}</div>
<div v-else class="el-upload__tip">{{ tip }}</div>
</div>
<image-viewer v-if="showViewer" :z-index="2000" :initial-index="0" :on-close="handleCloseViewer" :url-list="previewList" />
</div>
</template>
<script>
import ImageViewer from '@/components/Uploader/image-viewer'
import './uploadFile.scss'
export default {
name: 'PreviewFile',
components: { ImageViewer },
props: {
// 双向绑定的值
value: {
type: Object,
default: () => ({})
},
// 上传文件类型 picture: 图片 word: word文档
type: {
type: String,
default: 'picture'
},
// 上传水平照片还是垂直
vertical: {
type: Boolean,
default: false
},
tip: {
type: String,
default: ''
}
},
data() {
return {
showViewer: false
}
},
computed: {
/**
* 兜底展位图
*/
placeholderImage() {
// 如果当前是word
if (this.type === 'word') {
return require('@/assets/components/upload/ico_word.png')
}
// 如果当前是照片则判断横竖
if (this.type === 'picture') {
return this.vertical ? require('@/assets/components/upload/ico_pic_v.png') : require('@/assets/components/upload/ico_pic_h.png')
}
return ''
},
/**
* 图片icon的class类名
*/
imageIcon() {
// 如果当前是word
if (this.type === 'word') {
return 'icon-word'
}
if (this.type === 'picture') {
return this.vertical ? 'icon-pic-v' : 'icon-pic-h'
}
},
/**
* 预览列表
*/
previewList() {
return [this.value.url]
}
},
methods: {
/**
* 打开viewer,预览图片
*/
handleOpenViewer() {
// 如果是图片,则开始预览
if (this.type === 'picture') {
this.showViewer = true
} else {
window.location.href = this.value.fileUrl
}
},
/**
* 关闭预览图片
*/
handleCloseViewer() {
this.showViewer = false
}
}
}
</script>
<template>
<div class="component-upload-agreement">
<h1 :class="required ? 'required' : ''">{{ title }}</h1>
<el-form ref="form" :rules="required ? RULE : null" :model="value" class="upload-agreement" label-position="top" inline>
<el-form-item v-if="showWord" prop="word">
<template #label>
<span>Word文档</span>
<el-link type="primary" icon="el-icon-download" style="margin-left: 16px;" @click="handleDownload">下载模板</el-link>
</template>
<PreviewFile v-if="preview" :value="value.word || {}" type="word" />
<UploadFile v-else v-model="value.word" type="word" accept=".doc,.docx" tip="请上传docx格式文件,不大于2MB。" />
</el-form-item>
<el-form-item v-if="showVertical" :label="isLogo ? 'Web端' : '横版图片'" prop="vertical">
<PreviewFile v-if="preview" :value="value.vertical || {}" :vertical="true" type="picture" :tip="isLogo ? '333px * 84px' : '用于平板端手写签名'" />
<UploadFile v-else v-model="value.vertical" :vertical="true" type="picture" accept=".jpg,.jpeg,.png">
<template #tip>
<div>{{ isLogo ? '333px * 84px' : '用于平板端手写签名' }}</div>
<div>请上传jpg/jpeg、png图片文件,不大于1MB。</div>
</template>
</UploadFile>
</el-form-item>
<el-form-item v-if="showHorizontal" :label="isLogo ? 'H5端' : '竖版图片'" prop="horizontal">
<PreviewFile v-if="preview" :value="value.horizontal || {}" :vertical="false" type="picture" :tip="isLogo ? '621px * 144px' : '用于手机端手写签名'" />
<UploadFile v-else v-model="value.horizontal" :vertical="false" type="picture" accept=".jpg,.jpeg,.png">
<template #tip>
<div>{{ isLogo ? '621px * 144px' : '用于手机端手写签名' }}</div>
<div>请上传jpg/jpeg、png图片文件,不大于500KB。</div>
</template>
</UploadFile>
</el-form-item>
</el-form>
</div>
</template>
<script>
import UploadFile from './UploadFile'
import PreviewFile from './PreviewFile'
/**
* 校验图片,word的方法
* @param rule 当前规则
* @param value 当前选中的值
* @param callback 当前回调
*/
function validator(rule, value, callback) {
if (!value.uuid) {
callback(new Error('请上传文件'))
} else {
callback()
}
}
export default {
name: 'UploadAgreement',
components: { UploadFile, PreviewFile },
props: {
title: {
type: String,
default: ''
},
value: {
type: Object,
default: () => ({})
},
preview: {
type: Boolean,
default: true
},
required: {
type: Boolean,
default: true
},
templateUrl: {
type: String,
default: ''
},
// 是否展示word上传
showWord: {
type: Boolean,
default: true
},
// 是否展示红横版图片
showVertical: {
type: Boolean,
default: true
},
// 展示竖版图片
showHorizontal: {
type: Boolean,
default: true
},
// 是否是logo
isLogo: {
type: Boolean,
default: false
}
},
data() {
// 规则拷贝
const RULE_COPY = {}
// 如果需要展示word
if (this.showWord) {
RULE_COPY['word'] = { validator }
}
// 如果需要展示横版图片
if (this.showVertical) {
RULE_COPY['vertical'] = { validator }
}
if (this.showHorizontal) {
RULE_COPY['horizontal'] = { validator }
}
return { RULE: RULE_COPY }
},
methods: {
async validate() {
await this.$refs.form.validate()
},
/**
* 下载链接
*/
handleDownload() {
// 如果当前没有链接
if (!this.templateUrl) {
this.$message.error('模板链接获取失败')
return
}
// 开始下载
window.location.href = this.templateUrl
}
}
}
</script>
<style lang="scss">
.component-upload-agreement {
font-family: PingFangSC-Regular, PingFang SC;
h1 {
color: #71747B;
font-size: 14px;
font-weight: 400;
line-height: 20px;
margin: 0 0 24px;
&.required {
&:before {
content: '*';
color: #F56C6C;
display: inline;
margin-right: 6px;
}
}
}
.upload-agreement {
.el-form-item__label {
color: #71747B;
height: 20px;
line-height: 20px;
margin-bottom: 10px;
}
}
}
</style>
<template>
<el-upload
ref="upload"
:limit="1"
:data="params"
:headers="headers"
:file-list="value.uuid ? [value] : []"
:action="action"
:accept="accept"
:show-file-list="false"
:before-upload="onBefore"
:on-remove="onRemove"
:on-success="onSuccess"
:on-error="onError"
:on-exceed="onExceed"
class="word-uploader"
>
<template slot="trigger">
<img v-if="value.uuid" :src="value.url" class="imageicon">
<div v-else :class="imageIcon" class="imageicon" />
<div v-if="value.uuid" class="file-name">{{ value.name }}</div>
<el-button size="mini" round @click="handleClearFile">{{ value.name ? '重新选择' : '选择文件' }}</el-button>
<div class="el-upload__tip" v-if="!value.uuid">
<slot name="tip">{{ tip }}</slot>
</div>
</template>
</el-upload>
</template>
<script>
import { getToken } from '@/utils/auth'
import { postUploadFile } from '@/api/special-business'
import './uploadFile.scss'
export default {
name: 'UploadWord',
props: {
// 请求路径
action: {
type: String,
default: postUploadFile
},
// 请求头
headers: {
type: Object,
default: () => ({
'Authorization': `bearer ${getToken()}`
})
},
// 上传接口的额外参数
params: {
type: Object,
default: () => ({ rootPath: '', path: '' })
},
// 上传文件类型 picture: 图片 word: word文档
type: {
type: String,
default: 'picture'
},
// 上传水平照片还是垂直
vertical: {
type: Boolean,
default: false
},
// 提示信息
tip: {
type: String,
default: ''
},
// 允许选择的文件
accept: {
type: String,
default: ''
},
// 双向绑定的值
value: {
type: Object,
default: () => ({})
}
},
data() {
return {
loaded: false,
file: {}
}
},
computed: {
/**
* 图片icon的class类名
*/
imageIcon() {
// 如果当前是word
if (this.type === 'word') {
return 'icon-word'
}
if (this.type === 'picture') {
return this.vertical ? 'icon-pic-v' : 'icon-pic-h'
}
}
},
methods: {
/**
* 清空上传的文件
*/
handleClearFile() {
this.$emit('input', {})
},
/**
* 上传前校验
* @time 2021-12-06 10:02:49
*/
onBefore(file) {
// 当前选择的文件名
const fileName = file.name
// 后缀
const ext = fileName.slice(fileName.lastIndexOf('.'))
// 当前允许的文件类型
const accept = this.accept.split(',')
// 如果当前是不合法的
if (!accept.includes(ext)) {
this.$message.error(`上传的文件仅支持${this.accept}格式`)
return false
}
const isLt2M = file.size / 1024 / 1024 <= 2
if (!isLt2M) {
this.$message.error('上传文件大小不能超过2MB')
return false
}
// 呈现loading状态
this.loaded = true
},
/**
* 上传数量限制
* @time 2021-12-06 10:03:10
*/
onExceed() {
this.$message.error('最多上传1个文件')
// 关闭loading状态
this.loaded = false
},
/**
* 上传错误
* @param {Object} err 错误对象
* @time 2021-12-15 14:14:49
*/
onError() {
this.$message.error('文件上传失败')
this.$refs.upload.clearFiles()
this.onRemove()
// 关闭loading状态
this.loaded = false
},
/**
* 响应删除文件操作
* @time 2021-12-09 09:52:56
*/
onRemove() {
this.$emit('input', {})
},
/**
* 文件上传
* @time 2021-12-06 10:02:33
*/
onSuccess(json) {
if (json.success) {
this.$message.success('文件上传成功')
const data = json.data || {}
// 用于组件展示用
this.$emit('input', {
name: data.fileName,
url: this.type === 'word' ? require('@/assets/components/upload/ico_word_active.png') : data.accessUrl,
fileUrl: data.accessUrl,
uuid: data.uuid
})
}
// 关闭loading状态
this.loaded = false
}
}
}
</script>
.word-uploader {
align-items: center;
display: flex;
flex-direction: column;
justify-content: center;
.imageicon {
background-color: #F7F8FA;
background-repeat: no-repeat;
background-position: center center;
border-radius: 4px;
border: 1px dashed #CACCD0;
display: block;
width: 68px;
height: 68px;
object-fit: cover;
margin: 0 auto 8px;
&.icon-word {
background-image: url(../../../../assets/components/upload/ico_word.png);
background-size: 30px 30px;
}
&.icon-pic-v {
background-image: url(../../../../assets/components/upload/ico_pic_v.png);
background-size: 40px 30px;
}
&.icon-pic-h {
background-image: url(../../../../assets/components/upload/ico_pic_h.png);
background-size: 30px 40px;
}
}
.file-name {
color: #212026;
line-height: 18px;
margin-bottom: 8px;
}
.el-button {
color: #333942;
display: block;
}
.el-upload {
align-items: center;
background-color: transparent;
border: 1px dashed rgba(215, 219, 223, 1);
display: flex;
flex-direction: column;
width: 362px;
height: 168px;
justify-content: center;
.el-upload__tip {
color: rgba(132, 133, 138, 0.7);
font-size: 12px;
line-height: 18px;
text-align: center;
}
}
}
\ No newline at end of file
<template>
<div class="component-search-table">
<div class="component-search-table-container">
<div class="component-search-table-nav-title">协议管理</div>
<div class="component-search-table-form">
<el-form ref="formRef" :model="formData" :rules="RULES" label-position="left" size="small">
<el-row :gutter="12">
<el-col :span="isTablet ? 12 : 6">
<el-form-item label="组织" label-width="56px" prop="orgId">
<Organ v-model="formData.orgId" />
</el-form-item>
</el-col>
<el-col :span="6">
<div class="component-search-table-btn-wrap">
<el-button :loading="loading" type="primary" icon="el-icon-search" class="component-search-table-button" @click="handleSubmit">查询</el-button>
<el-button class="component-search-table-button clear" @click="handleReset"><i class="component-search-table-icon-clear" />清除</el-button>
</div>
</el-col>
</el-row>
</el-form>
</div>
<div class="component-search-table-table">
<UploadAgreement ref="peopleAgreementRef" title="个人入网协议" v-model="peopleAgreement" :template-url="downloadUrls.peopleMouldUrl" :preview="preview" />
</div>
<div class="component-search-table-table">
<UploadAgreement ref="companyAgreementRef" title="企业入网协议" v-model="companyAgreement" :template-url="downloadUrls.companyMouldUrl" :preview="preview" />
</div>
<div class="component-search-table-table">
<UploadAgreement ref="realnameNoticeRef" title="实名制责任告知书" v-model="realnameNotice" :template-url="downloadUrls.realnameMouldUrl" :preview="preview" />
</div>
<div class="component-search-table-table">
<UploadAgreement ref="companyAuthorizeRef" title="企业授权书" v-model="companyAuthorize" :show-vertical="false" :show-horizontal="false" :template-url="downloadUrls.authorizeMouldUrl" :preview="preview" />
</div>
<div class="component-search-table-table">
<UploadAgreement ref="otherRef" title="个人授权书" v-model="other" :show-vertical="false" :show-horizontal="false" :template-url="downloadUrls.otherMouldUrl" :preview="preview" />
</div>
<div class="component-search-table-table">
<UploadAgreement ref="logoRef" title="公司LOGO" v-model="logo" :show-word="false" :is-logo="true" :preview="preview" />
</div>
</div>
<div class="btn-wrapper">
<el-button v-if="preview" :loading="previewLoading" :disabled="!formData.orgId" type="primary" @click="handleClosePreview">编辑</el-button>
<template v-else>
<el-button @click="preview = true">取消</el-button>
<el-button type="primary" @click="handleConfirmSelect" :loading="submitLoading">提交</el-button>
</template>
</div>
</div>
</template>
<script>
import Organ from '@/components/Organ'
import UploadAgreement from './components/UploadAgreement'
import { queryPotocolManage, queryFileMould, updatePotocolManage, createPotocolManage } from '@/api/management'
import '@/components/SearchTable/index.scss'
const RULES = {
orgId: {
required: true,
message: '请选择组织',
trigger: 'change'
}
}
/**
* 创建协议文件对象
*/
function createAgreementFile(word = {}, vertical = {}, horizontal = {}) {
return {
word: { uuid: word.uuid, url: word.fileUrl ? require('@/assets/components/upload/ico_word_active.png') : '', fileUrl: word.fileUrl, name: word.fileName },
horizontal: { uuid: horizontal.uuid, url: horizontal.fileUrl, fileUrl: horizontal.fileUrl, name: horizontal.fileName },
vertical: { uuid: vertical.uuid, url: vertical.fileUrl, fileUrl: vertical.fileUrl, name: vertical.fileName }
}
}
/**
* 格式化成接口请求需要的数据
* @param data 当前需要处理的对象
* @param key 需要处理的字段
*/
function formatParams(data, key) {
// 取出word和图片资源
const { word, horizontal, vertical } = data
return {
[`${key}Word`]: word.uuid || '',
[`${key}Horizontal`]: horizontal.uuid || '',
[`${key}Vertical`]: vertical.uuid || ''
}
}
export default {
name: 'AgreementManage',
components: { Organ, UploadAgreement },
data() {
// 组织id
const { organId } = this.$store.getters
return {
loading: false,
submitLoading: false,
isSearched: false,
formData: {
orgId: organId
},
RULES,
// logo
logo: {
horizontal: '',
vertical: ''
},
// 是否请求过接口
isFetched: false,
// 下载的文件
downloadUrls: {},
// 编辑按钮的loading状态
previewLoading: false,
preview: true,
peopleAgreement: createAgreementFile(),
companyAgreement: createAgreementFile(),
realnameNotice: createAgreementFile(),
companyAuthorize: createAgreementFile(),
other: createAgreementFile(),
isTablet: window.OS.isTablet
}
},
mounted() {
this.handleSubmit()
this.fetchAgreementDownloadUrl()
},
methods: {
/**
* 提交方法
* @param formData 提交的表单数据
*/
async handleSubmit() {
try {
await this.$refs.formRef.validate()
} catch (error) {
return
}
// 呈现loading状态
this.loading = true
try {
// 获取接口返回值
const respData = await queryPotocolManage(this.formData) || {}
// 获取当前记录id
this.formData.uuid = respData.uuid
// 个人入网合同
this.peopleAgreement = createAgreementFile(
respData.peopleAgreementWord,
respData.peopleAgreementVertical,
respData.peopleAgreementHorizontal
)
// 企业入网合同
this.companyAgreement = createAgreementFile(
respData.companyAgreementWord,
respData.companyAgreementVertical,
respData.companyAgreementHorizontal
)
// 责任告知书
this.realnameNotice = createAgreementFile(
respData.realnameNoticeWord,
respData.realnameNoticeVertical,
respData.realnameNoticeHorizontal
)
// 企业授权书
this.companyAuthorize = createAgreementFile(
respData.companyAuthorizeWord
)
// 个人授权书
this.other = createAgreementFile(
respData.otherWord
)
// logo
this.logo = createAgreementFile(
{},
respData.logoPc,
respData.logoH5
)
} catch (error) {
console.error(error)
}
// 打开预览状态
this.preview = true
// 关闭loading状态
this.loading = false
},
/**
* 关闭预览模式
*/
async handleClosePreview() {
// 展示loading框
this.previewLoading = true
try {
// 加载一遍接口
await this.handleSubmit()
// 关闭预览模式
this.preview = false
} catch (error) {
console.error(error)
}
// 编辑按钮不展示loading框
this.previewLoading = false
},
/**
* 获取下载地址
*/
async fetchAgreementDownloadUrl() {
// 获取当前下载路径
this.downloadUrls = await queryFileMould(this.formData) || {}
},
/**
* 确认用户上传的文件
*/
async handleConfirmSelect() {
try {
// 先校验是否都输入完成
await Promise.all([
this.$refs.peopleAgreementRef.validate(),
this.$refs.companyAgreementRef.validate(),
this.$refs.realnameNoticeRef.validate(),
this.$refs.companyAuthorizeRef.validate(),
this.$refs.logoRef.validate(),
this.$refs.otherRef.validate()
])
} catch (error) {
return
}
// 提交按钮呈现loading状态
this.submitLoading = true
try {
// 请求方法
const requestFn = this.formData.uuid ? updatePotocolManage : createPotocolManage
// 开始创建协议
await requestFn({
...this.formData,
...formatParams(this.peopleAgreement, 'peopleAgreement'),
...formatParams(this.companyAgreement, 'companyAgreement'),
...formatParams(this.realnameNotice, 'realnameNotice'),
...formatParams(this.companyAuthorize, 'companyAuthorize'),
...formatParams(this.other, 'other'),
logoPc: this.logo.vertical.uuid,
logoH5: this.logo.horizontal.uuid
})
// 给出提示信息
this.$message.success(`${this.formData.uuid ? '修改' : '提交'}成功`)
// 重新请求一次接口
this.handleSubmit()
} catch (error) {
console.error('提交报错:', error)
}
// 提交按钮管理loading状态
this.submitLoading = false
},
/**
* 重置
*/
handleReset() {
this.formData.orgId = ''
}
}
}
</script>
<style lang="scss" scoped>
.component-search-table {
display: flex;
flex-direction: column;
height: 100%;
padding-bottom: 0px;
.component-search-table-container {
flex: 1;
overflow: auto;
padding-bottom: 12px;
}
.btn-wrapper {
align-items: center;
background: #FFFFFF;
box-shadow: 0px 0px 12px 0px rgba(196, 198, 207, 0.21);
border-radius: 0px 0px 0px 8px;
display: flex;
height: 64px;
justify-content: center;
}
}
</style>
<template>
<div v-loading.fullscreen.lock="fullscreenLoading" element-loading-spinner="page-loading" class="app-container">
<page-title />
<div class="search-form">
<el-form ref="formRef" :model="formData" label-position="left" label-width="70px">
<el-row :gutter="20">
<el-col :span="5">
<el-form-item label="所属组织">
<el-select v-model="formData.companyNo">
<el-option label="组织1" value="1" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="姓名">
<el-input v-model="formData.username" />
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="用户名">
<el-input v-model="formData.nickname" />
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="手机号">
<el-input v-model="formData.phone" />
</el-form-item>
</el-col>
<el-col :span="4">
<el-button round size="small" type="primary" icon="iconfont icon-search">搜索</el-button>
<el-button round size="small" type="gray" icon="iconfont icon-clear">清除</el-button>
</el-col>
</el-row>
</el-form>
</div>
<div class="table-list">
<el-table ref="tableRender" :data="list">
<el-table-column prop="username" label="姓名" />
<el-table-column prop="account" label="账户" />
<el-table-column prop="phone" label="手机号" />
<el-table-column prop="nickname" label="昵称" />
<el-table-column prop="role" label="角色" />
<el-table-column prop="status" label="用户状态" />
<el-table-column prop="company" label="所属组织" />
<el-table-column label="操作" width="200px">
<el-button type="text">编辑</el-button>
<el-button type="text">详情</el-button>
<el-button type="text">重置密码</el-button>
</el-table-column>
</el-table>
<el-pagination
:page-sizes="[20, 50, 100, 200, 300]"
:page-size="20"
:total="1"
:current-page="1"
layout="total, sizes, prev, pager, next, jumper"
/>
</div>
</div>
</template>
<script>
export default {
name: 'BaseManagement',
data() {
return {
fullscreenLoading: false,
list: [
{ username: '张三', account: '11', phone: '17625907745', nickname: '张三不散', role: 'admin', status: '启用', company: '宝马' }
],
formData: {},
pagination: {
total: 0,
currentPage: 1,
pageSize: 20
}
}
}
}
</script>
<template>
<el-tabs class="page-car-card">
<el-tab-pane label="查询">
<SearchTable
ref="querySearchTableRef"
:immediately="false"
v-model="queryFormData"
@reset="handleResetCarCard"
@submit="handleSubmitCarCard"
>
<template slot="slot-form">
<el-col :span="isTablet ? 12 : 8">
<el-form-item :rules="REQUIRED" label="组织" prop="organizationId" label-width="72px">
<CarCompany v-model="queryFormData.organizationId" :default-select-first="true" placeholder="请选择车厂" @change="$refs.querySearchTableRef && $refs.querySearchTableRef.handleSubmit()" />
</el-form-item>
</el-col>
<el-col :span="isTablet ? 12 : 8">
<el-form-item label="ICCID" label-width="72px" prop="iccid">
<el-input v-model="queryFormData.iccid" placeholder="请输入ICCID" />
</el-form-item>
</el-col>
<el-col :span="isTablet ? 12 : 8" :style="{ marginTop: isTablet ? '16px' : '0px' }">
<el-form-item label="VIN" label-width="72px" prop="vin">
<el-input v-model="queryFormData.vin" placeholder="请输入VIN号" />
</el-form-item>
</el-col>
<el-col :span="isTablet ? 24 : 8" style="margin-top: 16px;">
<el-form-item label="创建时间" label-width="72px" prop="vin">
<el-date-picker v-model="queryFormData.createTime" type="daterange" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" value-format="timestamp" />
</el-form-item>
</el-col>
</template>
<template #slot-table>
<el-table-column type="index" label="序号" width="80px" />
<el-table-column prop="organizationName" label="组织名称" min-width="140px" />
<el-table-column prop="telecomSupplier" label="通讯运营商" min-width="140px" />
<el-table-column prop="vin" label="VIN" min-width="170px" />
<el-table-column prop="iccid" label="ICCID" min-width="190px" />
<el-table-column prop="brandName" label="品牌名称" min-width="120px" />
<el-table-column prop="brand" label="车辆品牌" min-width="120px" />
<el-table-column prop="vehicleModel" label="车型" min-width="120px" />
<el-table-column prop="vehicleSeries" label="车系" min-width="120px" />
<el-table-column prop="years" label="年限" min-width="100px" />
<el-table-column prop="installLocation" label="卡位置" min-width="120px">
<template slot-scope="scope">
<span>{{ scope.row.installLocation === 1 ? '车机' : 'tbox' }}</span>
</template>
</el-table-column>
<el-table-column label="是否允许补录" min-width="120px">
<template slot-scope="scope">
<span>{{ scope.row.realBySelf ? '允许' : '不允许' }}</span>
</template>
</el-table-column>
<el-table-column prop="createTime" label="创建时间" min-width="170px" />
<el-table-column label="状态" min-width="100px">
<template slot-scope="scope">
<div class="status-wrap">
<i :class="scope.row.bindStatus == 0 ? 'green' : 'red'" class="status-point" />
{{ ['已启用', '已禁用'][scope.row.bindStatus] }}
</div>
</template>
</el-table-column>
<el-table-column label="操作" min-width="100px">
<template slot-scope="scope">
<el-link v-if="scope.row.bindStatus == 0" type="primary" @click="handleUnBind(scope.row)">禁用</el-link>
<el-link v-else type="primary" @click="handleBind(scope.row)">启用</el-link>
</template>
</el-table-column>
</template>
</SearchTable>
</el-tab-pane>
<el-tab-pane label="车卡导入">
<SearchTable
ref="importSearchTableRef"
v-model="importHistoryFormData"
:immediately="false"
@reset="handleResetImportHistory"
@submit="handleSubmitImportHistory"
>
<template slot="slot-form">
<el-col :span="isTablet ? 12 : 8">
<el-form-item :rules="REQUIRED" label="车厂" label-width="72px" prop="orgUuid">
<CarCompany v-model="importHistoryFormData.orgUuid" :default-select-first="true" placeholder="请选择车厂" @change="$refs.importSearchTableRef && $refs.importSearchTableRef.handleSubmit()" />
</el-form-item>
</el-col>
<el-col :span="isTablet ? 12 : 8">
<el-form-item label="处理结果" label-width="72px" prop="status">
<el-select v-model="importHistoryFormData.status" placeholder="请选择处理结果">
<el-option label="所有" value="" />
<el-option label="成功" value="1" />
<el-option label="错误" value="2" />
<el-option label="处理中" value="0" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="isTablet ? 24 : 8" :style="isTablet ? 'margin-top: 16px;' : ''">
<el-form-item label="处理时间" label-width="72px" prop="createTime">
<el-date-picker
v-model="importHistoryFormData.createTime"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="timestamp"
/>
</el-form-item>
</el-col>
<el-col :span="isTablet ? 12 : 8" style="margin-top: 16px;">
<el-form-item label="操作类型" label-width="72px" prop="status">
<el-select v-model="importHistoryFormData.fileType" placeholder="请选择操作类型">
<el-option label="全部" value="" />
<el-option label="新增" :value="1" />
<el-option label="启用" :value="4" />
<el-option label="禁用" :value="5" />
</el-select>
</el-form-item>
</el-col>
</template>
<template slot="slot-action-bar">
<el-button type="primary" icon="el-icon-plus" @click="handleShowCarCardImport">车卡导入</el-button>
</template>
<template #slot-table>
<el-table-column type="index" label="序号" width="100px" />
<el-table-column prop="fileName" label="上传文件名称">
<template slot-scope="scope">
<el-link @click="handleDownloadExcel(scope.row)">{{ scope.row.fileName }}</el-link>
</template>
</el-table-column>
<el-table-column label="上传状态" width="160px">
<template slot-scope="scope">
<el-tag v-if="scope.row.status === 1" type="success">成功</el-tag>
<el-tag v-else-if="scope.row.status === 2" type="danger">错误</el-tag>
<el-tag v-else type="warning">处理中</el-tag>
</template>
</el-table-column>
<el-table-column prop="totalCount" label="上传总数" width="160px" />
<el-table-column prop="successCount" label="成功数" width="160px" />
<el-table-column prop="errorCount" label="失败数" width="160px" />
<el-table-column prop="createTime" label="上传时间" />
<el-table-column prop="fileType" label="操作类型">
<template slot-scope="scope">
<div class="status-wrap">
<i :class="scope.row.fileType == 5 ? 'red' : 'green'" class="status-point" />
{{ { 1: '新增', 4: '启用', 5: '禁用' }[scope.row.fileType] }}
</div>
</template>
</el-table-column>
<el-table-column label="操作" prop="operation" width="160px">
<template slot-scope="scope">
<el-button v-if="scope.row.status === 2" type="text" @click="handleDownloadErrorExcel(scope.row)">错误信息</el-button>
</template>
</el-table-column>
</template>
</SearchTable>
<div class="rnr-dialog">
<el-dialog :visible.sync="showCarImport" title="车卡导入" width="960px">
<el-form ref="importFormRef" :model="importFormData" :rules="RULES" label-position="top">
<el-form-item label="组织" prop="orgUuid">
<CarCompany v-model="importFormData.orgUuid" placeholder="请选择组织" @change="handleCarCompanyChange" />
</el-form-item>
<el-form-item label="属性" prop="tagUuid">
<el-select v-model="importFormData.tagUuid" placeholder="请选择属性">
<el-option v-for="tag in tags" v-bind="tag" :key="tag.value" />
</el-select>
</el-form-item>
<el-form-item label="操作类型" prop="fileType">
<el-select v-model="importFormData.fileType" placeholder="请选择操作类型">
<el-option label="新增" :value="1" />
<el-option label="启用" :value="4" />
<el-option label="禁用" :value="5" />
</el-select>
</el-form-item>
<el-form-item label="上传文件" prop="fileUuid">
<template slot="label">
<span>上传文件</span>
<el-link type="primary" icon="el-icon-download" @click="downloadTemplateFile">下载模板</el-link>
</template>
<el-upload
ref="upload"
:limit="1"
:data="upload.data"
:headers="upload.headers"
:file-list="fileList"
:action="upload.action"
:before-upload="onBefore"
:on-remove="onRemove"
:on-success ="onSuccess"
:on-error ="onError"
:on-exceed="onExceed"
class="file-uploader"
accept=".xls,.xlsx"
name="file"
multiple>
<el-button slot="trigger" size="small" type="primary">选择文件</el-button>
<div slot="tip" class="el-upload__tip">只能上传excel文件文件大小不超过10MB记录数不超过5000条</div>
</el-upload>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="showCarImport = false"> </el-button>
<el-button :loading="dialogLoading" type="primary" @click="handleConfirmImport"> </el-button>
</span>
</el-dialog>
</div>
</el-tab-pane>
</el-tabs>
</template>
<script>
import { querySimVehicleByPage, queryImportHistory, carCardExcelTemplate, downloadFile, importSimVehicle, queryTag, unbindSimVehicle, bindSimVehicle, downloadExcelFile } from '@/api/management'
import dayjs from 'dayjs'
import SearchTable from '@/components/SearchTable'
import CarCompany from '@/components/CarCompany'
import { getToken } from '@/utils/auth'
import { postUploadFile } from '@/api/special-business'
import '../dealer/dialog.scss'
const RULES = {
orgUuid: {
required: true, trigger: 'change', message: '请选择车厂'
},
fileUuid: {
required: true, trigger: 'change', message: '请上传文件'
}
}
// 必填项
const REQUIRED = { required: true, trigger: 'change', message: '请选择车厂' }
export default {
name: 'CarManagement',
components: {
CarCompany,
SearchTable
},
data() {
return {
// 查询页面的表单数据
queryFormData: {
organizationId: '',
iccid: '',
vin: '',
createTime: [dayjs().startOf('day').valueOf(), dayjs().endOf('day').valueOf()]
},
// 导入历史的搜索表单数据
importHistoryFormData: {
createTime: [],
fileType: 1,
status: '',
orgUuid: ''
},
// 上传组件的数据
upload: {
data: {
rootPath: '',
path: ''
},
headers: {
'Authorization': `bearer ${getToken()}`
},
action: postUploadFile
},
// 导入弹框的车卡关系数据
importFormData: {
fileName: '',
fileType: 1,
fileUuid: '',
orgUuid: '',
tagUuid: ''
},
REQUIRED,
RULES,
tags: [],
fileList: [],
dialogLoading: false,
showCarImport: false,
isTablet: window.OS.isTablet
}
},
methods: {
/**
* 禁用
* @param row 当前行数据
*/
async handleUnBind(row) {
await unbindSimVehicle({
iccid: row.iccid,
organizationId: row.organizationId,
vin: row.vin
})
// 先给个提示
this.$message.success('禁用成功')
// 开始刷新界面
this.$refs.querySearchTableRef.handleSubmit()
},
/**
* 启用
* @param row 当前行数据
*/
async handleBind(row) {
await bindSimVehicle({
iccid: row.iccid,
organizationId: row.orgUuid,
vin: row.vin
})
// 先给个提示
this.$message.success('启用成功')
// 开始刷新界面
this.$refs.querySearchTableRef.handleSubmit()
},
/**
* 车企改变的方法
*/
async handleCarCompanyChange(orgUuid) {
// 列表数据
const list = await queryTag({ orgUuid })
// 当前标签
this.tags = (list || []).map(item => {
return {
label: item.tagName,
value: item.tagCode
}
})
},
/**
* 根据输入的内容查询车卡绑定的列表数据
*/
async handleSubmitCarCard(formData, callback) {
const formDataCopy = { ...formData }
// 如果当前选中了时间
if (formDataCopy.createTime) {
formDataCopy['startCreateTime'] = formDataCopy.createTime[0]
formDataCopy['endCreateTime'] = dayjs(formDataCopy.createTime[1]).endOf('day').valueOf()
delete formDataCopy.createTime
}
// 开始查询数据
const { list, totalCount } = await querySimVehicleByPage(formDataCopy)
// 赋值成功数量
list.forEach(item => {
item.successCount = item.totalCount - item.errorCount
})
// 开始渲染页面
callback({ list, totalCount })
},
/**
* 重置form表单数据
*/
handleResetCarCard() {
// 重置数据
this.queryFormData.organizationId = ''
this.queryFormData.iccid = ''
this.queryFormData.vin = ''
},
/**
* 根据输入的内容查询导入的历史数据
*/
async handleSubmitImportHistory(formData, callback) {
// 拷贝一份数据
const formDataCopy = { ...formData }
// 如果当前选中了时间
if (formDataCopy.createTime) {
formDataCopy['startCreateTime'] = formDataCopy.createTime[0]
formDataCopy['endCreateTime'] = dayjs(formDataCopy.createTime[1]).endOf('day').valueOf()
}
// 如果当前没有选择,即是全部
if (formDataCopy.status === '') {
delete formDataCopy.status
}
// 先删除数据
delete formDataCopy.createTime
// 开始查询数据
const { list, totalCount } = await queryImportHistory(formDataCopy, callback)
// 补充成功数
list.forEach(item => {
item.successCount = item.totalCount - item.errorCount
})
// 开始渲染页面
callback({ list, totalCount })
},
/**
* 重置导入的历史数据表单数据
*/
handleResetImportHistory() {
this.importHistoryFormData.orgUuid = ''
this.importHistoryFormData.createTime = []
this.importHistoryFormData.status = ''
},
/**
* 下载模板文件
*/
downloadTemplateFile() {
carCardExcelTemplate({ fileType: this.importFormData.fileType })
},
/**
* 上传前校验
* @time 2021-12-06 10:02:49
*/
onBefore(file) {
const type1 = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
const type2 = 'application/vnd.ms-excel'
let isExcel = false
if (file.type === type1 || file.type === type2) {
isExcel = true
}
const isLt10M = file.size / 1024 / 1024 <= 10
if (!isExcel) {
this.$message.error('车卡信息文件只支持excel文件')
return false
}
if (!isLt10M) {
this.$message.error('车卡信息文件大小不能超过10MB')
return false
}
},
/**
* 上传错误
* @param {Object} err 错误对象
* @time 2021-12-15 14:14:49
*/
onError() {
this.$message.error('文件上传失败')
this.$refs.upload.clearFiles()
this.onRemove()
},
/**
* 响应删除文件操作
* @time 2021-12-09 09:52:56
*/
onRemove(file, fileList) {
this.form = {
fileId: '',
checkData: {},
fileList: []
}
this.$emit('check', this.form)
},
/**
* 上传数量限制
* @time 2021-12-06 10:03:10
*/
onExceed() {
this.$message.error('最多上传1个excel文件')
},
/**
* 文件上传
* @time 2021-12-06 10:02:33
*/
onSuccess(json) {
if (json.success) {
this.$message.success('文件上传成功')
const data = json.data || {}
// 用于组件展示用
this.fileList = [{
name: data.fileName,
url: data.accessUrl,
uuid: data.uuid
}]
// 开始保存接口请求需要的数据
this.importFormData.fileName = data.fileName
this.importFormData.fileUuid = data.uuid
// 开始校验字段
this.$refs.importFormRef.validateField('fileUuid')
}
},
/**
* 下载错误的excel
* @param row 行数据
*/
handleDownloadErrorExcel(row) {
downloadFile({ uuid: row.uuid })
},
/**
* 下载excel文件
*/
handleDownloadExcel(row) {
downloadExcelFile({ uuid: row.uuid })
},
/**
* 用户导入的数据开始请求数据
*/
async handleConfirmImport() {
try {
await this.$refs.importFormRef.validate()
} catch (error) {
console.log(error)
return
}
this.dialogLoading = true
try {
// 开始请求接口
await importSimVehicle(this.importFormData)
// 关闭弹框,开始查询一遍数据
this.showCarImport = false
// 重新刷新页面
this.$refs.importSearchTableRef.handleSubmit()
} catch (error) {
console.error(error)
}
this.dialogLoading = false
},
/**
* 展示车卡上传的弹出框
*/
handleShowCarCardImport() {
// 清空已经上传的文件列表
this.fileList = []
// 展示弹框
this.showCarImport = true
// 等页面渲染完成后
this.$nextTick(() => {
// 先重置表单
this.$refs.importFormRef.resetFields()
})
}
}
}
</script>
<style lang="scss">
.page-car-card {
.el-tabs__header {
padding: 24px 24px 0;
}
.component-search-table {
padding-top: 0;
}
.el-col-6 {
margin-top: 16px;
}
.status-wrap {
align-items: center;
display: flex;
.status-point {
border-radius: 3px;
display: inline-block;
width: 6px;
height: 6px;
margin-right: 8px;
&.green {
background-color: #25C343;
}
&.red {
background-color: #FF4D4F;
}
}
}
}
</style>
<template>
<el-tabs class="page-car-info">
<el-tab-pane label="查询">
<SearchTable
ref="querySearchTableRef"
:immediately="false"
v-model="queryFormData"
@reset="handleResetCarCard"
@submit="handleSubmitCarCard"
>
<template slot="slot-form">
<el-col :span="isTablet ? 12 : 6">
<el-form-item :rules="REQUIRED" label="组织" prop="orgId" label-width="72px">
<CarCompany v-model="queryFormData.orgId" :default-select-first="true" placeholder="请选择车厂" @change="$refs.querySearchTableRef && $refs.querySearchTableRef.handleSubmit()" />
</el-form-item>
</el-col>
<el-col :span="isTablet ? 12 : 6">
<el-form-item label="VIN" label-width="72px" prop="vin">
<el-input v-model="queryFormData.vin" placeholder="请输入VIN号" />
</el-form-item>
</el-col>
<el-col :span="isTablet ? 24 : 6" :style="{ marginTop: isTablet ? '16px' : '0px' }">
<el-form-item label="创建时间" label-width="72px" prop="vin">
<el-date-picker v-model="queryFormData.createTime" type="daterange" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" value-format="timestamp" />
</el-form-item>
</el-col>
</template>
<template #slot-table>
<el-table-column type="index" label="序号" width="80px" />
<el-table-column prop="nameVehicleEnterprise" label="生产企业名称" min-width="140px" />
<el-table-column prop="vin" label="VIN" min-width="140px" />
<el-table-column prop="licensePlateNumber" label="车辆号码" min-width="100px" />
<el-table-column prop="vehicleType" label="车辆类型" min-width="170px" />
<el-table-column prop="placeOfOriginOfVehicle" label="车辆产地" min-width="190px" />
<el-table-column prop="vehicleDepartment" label="车辆品牌" min-width="120px" />
<el-table-column prop="vehicleName" label="车辆名称" min-width="120px" />
<el-table-column prop="vehicleNum" label="车辆型号" min-width="120px" />
<el-table-column prop="vehicleModel" label="车型通用名称" min-width="120px" />
<el-table-column prop="bodyColor" label="车身颜色" min-width="120px" />
<el-table-column prop="fuelType" label="燃料种类" min-width="120px" />
<el-table-column label="操作">
<template slot-scope="scope">
<el-link type="primary" @click="handleCarDetail(scope.row)">详情</el-link>
</template>
</el-table-column>
</template>
</SearchTable>
<el-dialog class="rnr-dialog" :visible.sync="showCarDetail" title="车辆详情" width="960px">
<el-form ref="importFormRef" :model="importFormData" :rules="RULES" label-position="top" style="height: 400px; overflow: auto;">
<el-row>
<el-col :span="12" class="el-col-mar no-mar-top">
<el-form-item label="生产企业名称">
<el-input readonly :value="carDetail.nameVehicleEnterprise" />
</el-form-item>
</el-col>
<el-col :span="12" class="el-col-mar no-mar-top">
<el-form-item label="VIN">
<el-input readonly :value="carDetail.vin" />
</el-form-item>
</el-col>
<el-col :span="12" class="el-col-mar">
<el-form-item label="车辆类型">
<el-input readonly :value="carDetail.vehicleType" />
</el-form-item>
</el-col>
<el-col :span="12" class="el-col-mar">
<el-form-item label="车辆产地">
<el-input readonly :value="carDetail.placeOfOriginOfVehicle" />
</el-form-item>
</el-col>
<el-col :span="12" class="el-col-mar">
<el-form-item label="车辆品牌">
<el-input readonly :value="carDetail.vehicleDepartment" />
</el-form-item>
</el-col>
<el-col :span="12" class="el-col-mar">
<el-form-item label="车辆名称">
<el-input readonly :value="carDetail.vehicleName" />
</el-form-item>
</el-col>
<el-col :span="12" class="el-col-mar">
<el-form-item label="车辆型号">
<el-input readonly :value="carDetail.vehicleNum" />
</el-form-item>
</el-col>
<el-col :span="12" class="el-col-mar">
<el-form-item label="车型通用名称">
<el-input readonly :value="carDetail.vehicleModel" />
</el-form-item>
</el-col>
<el-col :span="12" class="el-col-mar">
<el-form-item label="车身颜色">
<el-input readonly :value="carDetail.bodyColor" />
</el-form-item>
</el-col>
<el-col :span="12" class="el-col-mar">
<el-form-item label="燃料种类">
<el-input readonly :value="carDetail.fuelType" />
</el-form-item>
</el-col>
<el-col :span="12" class="el-col-mar">
<el-form-item label="发动机号码">
<el-input readonly :value="carDetail.engineNum" />
</el-form-item>
</el-col>
<el-col :span="12" class="el-col-mar">
<el-form-item label="电动机序列号">
<el-input readonly :value="carDetail.motorNum" />
</el-form-item>
</el-col>
<el-col :span="12" class="el-col-mar">
<el-form-item label="车辆出厂时间">
<el-input readonly :value="carDetail.vehicleDepartureTime" />
</el-form-item>
</el-col>
<el-col :span="12" class="el-col-mar">
<el-form-item label="车辆销售时间">
<el-input readonly :value="carDetail.vehicleSalesTime" />
</el-form-item>
</el-col>
<el-col :span="12" class="el-col-mar">
<el-form-item label="车辆销售信息变更时间">
<el-input readonly :value="carDetail.vehicleSalesUpdateTime" />
</el-form-item>
</el-col>
<el-col :span="12" class="el-col-mar">
<el-form-item label="车牌号码">
<el-input readonly :value="carDetail.licensePlateNumber" />
</el-form-item>
</el-col>
<el-col :span="12" class="el-col-mar">
<el-form-item label="车辆销售渠道名称">
<el-input readonly :value="carDetail.vehicleChannelName" />
</el-form-item>
</el-col>
<el-col :span="12" class="el-col-mar">
<el-form-item label="车辆销售渠道类型">
<el-input readonly :value="carDetail.vehicleChannelType" />
</el-form-item>
</el-col>
<el-col :span="12" class="el-col-mar">
<el-form-item label="车辆销售渠道员工姓名">
<el-input readonly :value="carDetail.vehicleStaffName" />
</el-form-item>
</el-col>
<el-col :span="12" class="el-col-mar">
<el-form-item label="车辆销售渠道地址">
<el-input readonly :value="carDetail.vehicleLogginAddress" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button type="primary" @click="showCarDetail = false">关 闭</el-button>
</span>
</el-dialog>
</el-tab-pane>
<el-tab-pane label="车辆导入">
<SearchTable
ref="importSearchTableRef"
v-model="importHistoryFormData"
:immediately="false"
@reset="handleResetImportHistory"
@submit="handleSubmitImportHistory"
>
<template slot="slot-form">
<el-col :span="isTablet ? 12 : 6">
<el-form-item :rules="REQUIRED" label="车厂" label-width="72px" prop="orgUuid">
<CarCompany v-model="importHistoryFormData.orgUuid" :default-select-first="true" placeholder="请选择车厂" @change="$refs.importSearchTableRef && $refs.importSearchTableRef.handleSubmit()" />
</el-form-item>
</el-col>
<el-col :span="isTablet ? 12 : 6">
<el-form-item label="处理结果" label-width="72px" prop="status">
<el-select v-model="importHistoryFormData.status" placeholder="请选择处理结果">
<el-option label="所有" value="" />
<el-option label="成功" value="1" />
<el-option label="错误" value="2" />
<el-option label="处理中" value="0" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="isTablet ? 24 : 6" :style="isTablet ? 'margin-top: 16px;' : ''">
<el-form-item label="处理时间" label-width="72px" prop="createTime">
<el-date-picker
v-model="importHistoryFormData.createTime"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="timestamp"
/>
</el-form-item>
</el-col>
</template>
<template slot="slot-action-bar">
<el-button type="primary" icon="el-icon-plus" @click="handleShowCarCardImport">车辆信息导入</el-button>
</template>
<template #slot-table>
<el-table-column type="index" label="序号" width="100px" />
<el-table-column prop="fileName" label="上传文件名称">
<template slot-scope="scope">
<el-link @click="handleDownloadExcel(scope.row)">{{ scope.row.fileName }}</el-link>
</template>
</el-table-column>
<el-table-column label="上传状态" width="160px">
<template slot-scope="scope">
<el-tag v-if="scope.row.status === 1" type="success">成功</el-tag>
<el-tag v-else-if="scope.row.status === 2" type="danger">错误</el-tag>
<el-tag v-else type="warning">处理中</el-tag>
</template>
</el-table-column>
<el-table-column prop="totalCount" label="上传总数" width="160px" />
<el-table-column prop="successCount" label="成功数" width="160px" />
<el-table-column prop="errorCount" label="失败数" width="160px" />
<el-table-column prop="createTime" label="上传时间" />
<el-table-column label="操作" prop="operation" width="200px">
<template slot-scope="scope">
<el-button v-if="scope.row.status === 2" type="text" @click="handleDownloadErrorExcel(scope.row)">错误信息</el-button>
</template>
</el-table-column>
</template>
</SearchTable>
<div class="rnr-dialog">
<el-dialog :visible.sync="showCarImport" title="车辆信息导入" width="960px">
<el-form ref="importFormRef" :model="importFormData" :rules="RULES" label-position="top">
<el-form-item label="车厂" prop="orgUuid">
<CarCompany v-model="importFormData.orgUuid" placeholder="请选择车厂" />
</el-form-item>
<el-form-item label="上传文件" prop="fileUuid">
<template slot="label">
<span>上传文件</span>
<el-link type="primary" icon="el-icon-download" @click="downloadTemplateFile">下载模板</el-link>
</template>
<el-upload
ref="upload"
:limit="1"
:data="upload.data"
:headers="upload.headers"
:file-list="fileList"
:action="upload.action"
:before-upload="onBefore"
:on-remove="onRemove"
:on-success ="onSuccess"
:on-error ="onError"
:on-exceed="onExceed"
class="file-uploader"
accept=".xls,.xlsx"
name="file"
multiple>
<el-button slot="trigger" size="small" type="primary">选择文件</el-button>
<div slot="tip" class="el-upload__tip">只能上传excel文件,文件大小不超过10MB,记录数不超过5000条</div>
</el-upload>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="showCarImport = false">取 消</el-button>
<el-button :loading="dialogLoading" type="primary" @click="handleConfirmImport">确 定</el-button>
</span>
</el-dialog>
</div>
</el-tab-pane>
</el-tabs>
</template>
<script>
import { queryCarInfo, queryImportHistory, downloadCarInfoTemplate, downloadFile, importCarInfo, unbindSimVehicle, bindSimVehicle, downloadExcelFile } from '@/api/management'
import dayjs from 'dayjs'
import SearchTable from '@/components/SearchTable'
import CarCompany from '@/components/CarCompany'
import { getToken } from '@/utils/auth'
import { postUploadFile } from '@/api/special-business'
import '../dealer/dialog.scss'
const RULES = {
orgUuid: {
required: true, trigger: 'change', message: '请选择车厂'
},
fileUuid: {
required: true, trigger: 'change', message: '请上传文件'
}
}
// 必填项
const REQUIRED = { required: true, trigger: 'change', message: '请选择车厂' }
export default {
name: 'CarManagement',
components: {
CarCompany,
SearchTable
},
data() {
return {
// 查询页面的表单数据
queryFormData: {
orgId: '',
iccid: '',
vin: '',
createTime: [dayjs().startOf('day').valueOf(), dayjs().endOf('day').valueOf()]
},
// 导入历史的搜索表单数据
importHistoryFormData: {
createTime: [],
fileType: 2,
status: '',
orgUuid: ''
},
// 上传组件的数据
upload: {
data: {
rootPath: '',
path: ''
},
headers: {
'Authorization': `bearer ${getToken()}`
},
action: postUploadFile
},
// 导入弹框的车卡关系数据
importFormData: {
fileName: '',
fileType: 2,
fileUuid: '',
orgUuid: '',
tagUuid: ''
},
REQUIRED,
RULES,
tags: [],
fileList: [],
carDetail: {},
dialogLoading: false,
showCarImport: false,
showCarDetail: false,
isTablet: window.OS.isTablet
}
},
methods: {
/**
* 查询车辆详情
*/
handleCarDetail(row) {
// 记录当前点击详情的数据
this.carDetail = row
// 展示详情
this.showCarDetail = true
},
/**
* 禁用
* @param row 当前行数据
*/
async handleUnBind(row) {
await unbindSimVehicle({
iccid: row.iccid,
orgId: row.orgId,
vin: row.vin
})
// 先给个提示
this.$message.success('禁用成功')
// 开始刷新界面
this.$refs.querySearchTableRef.handleSubmit()
},
/**
* 启用
* @param row 当前行数据
*/
async handleBind(row) {
await bindSimVehicle({
iccid: row.iccid,
orgId: row.orgId,
vin: row.vin
})
// 先给个提示
this.$message.success('启用成功')
// 开始刷新界面
this.$refs.querySearchTableRef.handleSubmit()
},
/**
* 根据输入的内容查询车卡绑定的列表数据
*/
async handleSubmitCarCard(formData, callback) {
const formDataCopy = { ...formData }
// 如果当前选中了时间
if (formDataCopy.createTime && formDataCopy.createTime.length === 2) {
formDataCopy['startTime'] = formDataCopy.createTime[0]
formDataCopy['endTime'] = dayjs(formDataCopy.createTime[1]).endOf('day').valueOf()
}
delete formDataCopy.createTime
// 开始查询数据
const { list, totalCount } = await queryCarInfo(formDataCopy)
// 赋值成功数量
list.forEach(item => {
item.successCount = item.totalCount - item.errorCount
})
// 开始渲染页面
callback({ list, totalCount })
},
/**
* 重置form表单数据
*/
handleResetCarCard() {
// 重置数据
this.queryFormData.orgId = ''
this.queryFormData.iccid = ''
this.queryFormData.vin = ''
this.queryFormData.createTime = []
this.queryFormData.fileType = 2
},
/**
* 根据输入的内容查询导入的历史数据
*/
async handleSubmitImportHistory(formData, callback) {
// 拷贝一份数据
const formDataCopy = { ...formData, fileType: 2 }
// 如果当前选中了时间
if (formDataCopy.createTime && formDataCopy.createTime.length === 2) {
formDataCopy['startCreateTime'] = formDataCopy.createTime[0]
formDataCopy['endCreateTime'] = dayjs(formDataCopy.createTime[1]).endOf('day').valueOf()
}
// 如果当前没有选择,即是全部
if (formDataCopy.status === '') {
delete formDataCopy.status
}
// 先删除数据
delete formDataCopy.createTime
// 开始查询数据
const { list, totalCount } = await queryImportHistory(formDataCopy, callback)
// 补充成功数
list.forEach(item => {
item.successCount = item.totalCount - item.errorCount
})
// 开始渲染页面
callback({ list, totalCount })
},
/**
* 重置导入的历史数据表单数据
*/
handleResetImportHistory() {
this.importHistoryFormData.orgUuid = ''
this.importHistoryFormData.createTime = []
this.importHistoryFormData.status = ''
},
/**
* 下载模板文件
*/
downloadTemplateFile() {
downloadCarInfoTemplate({ fileType: 3 })
},
/**
* 上传前校验
* @time 2021-12-06 10:02:49
*/
onBefore(file) {
const type1 = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
const type2 = 'application/vnd.ms-excel'
let isExcel = false
if (file.type === type1 || file.type === type2) {
isExcel = true
}
const isLt10M = file.size / 1024 / 1024 <= 10
if (!isExcel) {
this.$message.error('车卡信息文件只支持excel文件')
return false
}
if (!isLt10M) {
this.$message.error('车卡信息文件大小不能超过10MB')
return false
}
},
/**
* 上传错误
* @param {Object} err 错误对象
* @time 2021-12-15 14:14:49
*/
onError() {
this.$message.error('文件上传失败')
this.$refs.upload.clearFiles()
this.onRemove()
},
/**
* 响应删除文件操作
* @time 2021-12-09 09:52:56
*/
onRemove(file, fileList) {
this.form = {
fileId: '',
checkData: {},
fileList: []
}
this.$emit('check', this.form)
},
/**
* 上传数量限制
* @time 2021-12-06 10:03:10
*/
onExceed() {
this.$message.error('最多上传1个excel文件')
},
/**
* 文件上传
* @time 2021-12-06 10:02:33
*/
onSuccess(json) {
if (json.success) {
this.$message.success('文件上传成功')
const data = json.data || {}
// 用于组件展示用
this.fileList = [{
name: data.fileName,
url: data.accessUrl,
uuid: data.uuid
}]
// 开始保存接口请求需要的数据
this.importFormData.fileName = data.fileName
this.importFormData.fileUuid = data.uuid
// 开始校验字段
this.$refs.importFormRef.validateField('fileUuid')
}
},
/**
* 下载错误的excel
* @param row 行数据
*/
handleDownloadErrorExcel(row) {
downloadFile({ uuid: row.uuid })
},
/**
* 下载excel文件
*/
handleDownloadExcel(row) {
downloadExcelFile({ uuid: row.uuid })
},
/**
* 用户导入的数据开始请求数据
*/
async handleConfirmImport() {
try {
await this.$refs.importFormRef.validate()
} catch (error) {
console.log(error)
return
}
this.dialogLoading = true
try {
// 开始请求接口
await importCarInfo(this.importFormData)
// 关闭弹框,开始查询一遍数据
this.showCarImport = false
// 重新刷新页面
this.$refs.importSearchTableRef.handleSubmit()
} catch (error) {
console.error(error)
}
this.dialogLoading = false
},
/**
* 展示车卡上传的弹出框
*/
handleShowCarCardImport() {
// 清空已经上传的文件列表
this.fileList = []
// 展示弹框
this.showCarImport = true
// 等页面渲染完成后
this.$nextTick(() => {
// 先重置表单
this.$refs.importFormRef.resetFields()
})
}
}
}
</script>
<style lang="scss">
.page-car-info {
.el-tabs__header {
padding: 24px 24px 0;
}
.component-search-table {
padding-top: 0;
}
.status-wrap {
align-items: center;
display: flex;
.status-point {
border-radius: 3px;
display: inline-block;
width: 6px;
height: 6px;
margin-right: 8px;
&.green {
background-color: #25C343;
}
&.red {
background-color: #FF4D4F;
}
}
}
.el-col-mar {
padding: 0 12px;
margin-top: 24px;
}
.no-mar-top {
margin-top: 0px;
}
}
.tablet-adapter {
.page-car-info {
.component-search-table-btn-wrap {
margin-top: 16px;
}
}
}
</style>
<template>
<div>
<el-dialog
:visible="visible"
:title="'变更管理员'"
:close-on-click-modal="false"
:close-on-press-escape="false"
class="rnr-dialog"
width="960px"
destroy-on-close
@close="$emit('update:visible', false)"
>
<el-radio-group v-model="type">
<el-radio :label="0">用其他用户替换</el-radio>
<el-radio :label="1">用新账户替换</el-radio>
</el-radio-group>
<el-form ref="formRef" :model="formData[type]" label-position="top" style="margin-top: 24px;">
<!-- 当上面选择其他用户替换时出现 -->
<el-form-item v-if="type == 0" :rules="IS_NOT_EMPTY('请选择其他用户账户')" prop="newAdminUserId" label="其他用户账户">
<el-select v-model="formData[0].newAdminUserId" clearable placeholder="请选择其他用户账户">
<el-option v-for="user in userList[organId]" :key="user.value" v-bind="user" />
</el-select>
</el-form-item>
<!-- 当上面选择用新账户替换时出现 -->
<template v-else>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item :rules="IS_NOT_EMPTY('请输入管理员姓名')" prop="createAdminUserName" label="管理员姓名">
<el-input v-model="formData[1].createAdminUserName" placeholder="请输入管理员姓名" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item :rules="IS_NOT_EMPTY('请输入管理员账号')" prop="createAdminAccount" label="管理员账号">
<el-input v-model="formData[1].createAdminAccount" placeholder="请输入管理员账号" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item :rules="[IS_NOT_EMPTY('请输入管理员密码'), IS_RIGHT_PASSWORD()]" prop="createAdminPassword" label="管理员密码">
<el-input v-model="formData[1].createAdminPassword" type="password" placeholder="请输入管理员密码" />
<div class="el-form-item__field-tip">密码长度必须为8~20位字符,由大写字母、小写字母、数字、特殊符号中的3种及以上类型组成</div>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item :rules="[IS_NOT_EMPTY('请输入确认密码'), CONFIRM_PASSWORD]" prop="confirmPassword" label="确认密码">
<el-input v-model="formData[1].confirmPassword" type="password" placeholder="请确认密码" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item :rules="[IS_NOT_EMPTY('请输入管理员手机号'), IS_PHONE()]" prop="createAdminPhone" label="管理员手机号">
<el-input v-model="formData[1].createAdminPhone" placeholder="请输入管理员手机号" />
</el-form-item>
</el-col>
</el-row>
</template>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="handleClose">取消</el-button>
<el-button :loading="isLoading" type="primary" @click="handleSubmit">确定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import { changeUserEnterpriseDistributor, queryUserEnterpriseAccount, queryUserAccount, changeOrganAdmin } from '@/api/management'
import { IS_NOT_EMPTY, IS_PHONE, CONFIRM_PASSWORD, IS_RIGHT_PASSWORD } from '../../rules'
import '../dialog.scss'
export default {
name: 'ModifyAdministrator',
props: {
visible: {
type: Boolean,
default: false
},
data: {
type: Object,
default: () => {}
},
from: {
type: String,
default: ''
}
},
data() {
return {
IS_NOT_EMPTY,
IS_PHONE,
IS_RIGHT_PASSWORD,
isLoading: false,
type: 0,
userList: {},
organId: '',
formData: [
{ newAdminUserId: '' },
{
createAdminUserName: '',
createAdminAccount: '',
createAdminPassword: '',
createAdminPhone: ''
}
]
}
},
computed: {
/**
* 确认密码
*/
CONFIRM_PASSWORD() {
return CONFIRM_PASSWORD(this.formData[this.type].createAdminPassword)
}
},
watch: {
/**
* 如果当前是可见
*/
visible() {
// 如果当前不可见不调用接口
if (!this.visible) {
// 清空用户输入
this.formData = [
{ newAdminUserId: '' },
{
createAdminUserName: '',
createAdminAccount: '',
createAdminPassword: '',
createAdminPhone: ''
}
]
return
}
// 开始查询账户信息
this.queryUserEnterpriseAccount()
}
},
methods: {
/**
* 查询用户列表
*/
async queryUserEnterpriseAccount() {
// 取出id和租户号
const { uuid, id, tenantNo } = this.data
// 如果当前是组织
const requestFn = this.from === 'organ' ? queryUserAccount : queryUserEnterpriseAccount
// 组织id
this.organId = this.from === 'organ' ? uuid : id
// 如果当前组织之前请求过数据
if (this.userList[this.organId] && this.userList[this.organId].length > 0) {
return
}
// 开始请求接口数据
const respData = await requestFn({
organId: this.organId,
tenantNo,
currPage: 1,
pageSize: 20
})
// 当前列表数据
const list = this.from === 'organ' ? respData : respData.list
// 开始绑定数据
this.$set(this.userList, this.organId, list.map(item => ({
label: this.from === 'organ' ? item.fullName : item.userName,
value: item.id || item.uuid
})))
},
/**
* 关闭弹框
*/
handleClose() {
this.$emit('update:visible', false)
},
/**
* 点击提交方法
*/
handleSubmit() {
// 校验表格数据
this.$refs.formRef.validate(async valid => {
// 校验失败
if (!valid) {
return
}
// 按钮出现loading状态
this.isLoading = true
try {
// 其他参数
const { id, uuid, distributorAdminUserId, bizType, organAdminUserId, tenantNo } = this.data
// 接口请求数据
const formData = { ...this.formData[this.type] }
// 如果当前是组织,则请求组织接口
if (this.from === 'organ') {
await changeOrganAdmin({
...formData,
uuid,
bizType,
tenantNo,
currentAdminUserId: organAdminUserId
})
} else {
// 更换管理员
await changeUserEnterpriseDistributor({
...formData,
id,
currentAdminUserId: distributorAdminUserId
})
}
// 关闭弹框
this.handleClose()
// 刷新数据
this.$emit('refresh')
} catch (error) {
console.error(error)
}
// 关闭loading状态
this.isLoading = false
})
}
}
}
</script>
<template>
<el-dialog
:visible="visible"
:title="`${type === 'add' ? '新增' : '修改'}经销商`"
:close-on-click-modal="false"
:close-on-press-escape="false"
class="rnr-dialog"
width="960px"
destroy-on-close
@close="$emit('update:visible', false)"
>
<el-form ref="formRef" :model="data" label-position="top">
<el-row :gutter="24">
<el-col :span="12">
<el-form-item :rules="IS_NOT_EMPTY('请输入经销商名称')" prop="distributorName" label="经销商名称">
<el-input v-model="data.distributorName" placeholder="请输入经销商名称" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="备注">
<el-input v-model="data.remark" placeholder="请输入备注" />
</el-form-item>
</el-col>
</el-row>
<el-row v-show="type === 'add'" :gutter="24">
<el-col :span="12">
<el-form-item :rules="IS_NOT_EMPTY('请输入管理员姓名')" prop="distributorAdminUserName" label="管理员姓名">
<el-input v-model="data.distributorAdminUserName" placeholder="请输入管理员姓名" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item :rules="IS_NOT_EMPTY('请输入管理员账号')" prop="distributorAdminUserAccount" label="管理员账号">
<el-input v-model="data.distributorAdminUserAccount" placeholder="请输入管理员账号" />
</el-form-item>
</el-col>
</el-row>
<el-row v-show="type === 'add'" :gutter="24">
<el-col :span="12">
<el-form-item :rules="[IS_NOT_EMPTY('请输入管理员密码'), IS_RIGHT_PASSWORD()]" prop="password" label="管理员密码">
<el-input v-model="data.password" :placeholder="type === 'add' ? '请输入管理员密码' : '******'" type="password" />
<div class="el-form-item__field-tip">密码长度必须为8~20位字符,由大写字母、小写字母、数字、特殊符号中的3种及以上类型组成</div>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item :rules="[IS_NOT_EMPTY('请输入确认密码'), CONFIRM_PASSWORD]" prop="confirmPassword" label="确认密码">
<el-input v-model="data.confirmPassword" :placeholder="type === 'add' ? '请确认输入的密码' : '******'" type="password" />
</el-form-item>
</el-col>
</el-row>
<el-row v-show="type === 'add'" :gutter="24">
<el-col :span="12">
<el-form-item :rules="[IS_NOT_EMPTY('请输入管理员手机号'), IS_PHONE()]" prop="phone" label="管理员手机号">
<el-input v-model="data.phone" type="number" placeholder="请输入管理员手机号" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="handleClose()">取消</el-button>
<el-button :loading="isLoading" type="primary" @click="handleSubmit">确定</el-button>
</span>
</el-dialog>
</template>
<script>
import { addUserEnterpriseDistributor, updateUserEnterpriseDistributor } from '@/api/management'
import { IS_NOT_EMPTY, IS_PHONE, CONFIRM_PASSWORD, IS_RIGHT_PASSWORD } from '../../rules'
import '../dialog.scss'
export default {
props: {
visible: {
type: Boolean,
default: false
},
data: {
type: Object,
default: () => ({})
},
type: {
type: String,
default: 'add'
}
},
data() {
return {
IS_NOT_EMPTY,
IS_PHONE,
IS_RIGHT_PASSWORD,
isLoading: false
}
},
computed: {
/**
* 确认密码
*/
CONFIRM_PASSWORD() {
return CONFIRM_PASSWORD(this.data.password)
}
},
methods: {
/**
* 点击关闭方法
*/
handleClose() {
this.$emit('update:visible', false)
},
/**
* 点击保存方法
*/
handleSubmit() {
// 对输入的数据进行校验
this.$refs.formRef.validate(async valid => {
// 如果校验失败
if (!valid) {
return
}
// 展示loading状态
this.isLoading = true
try {
// 如果当前是新增
if (this.type === 'add') {
await addUserEnterpriseDistributor(this.data)
}
// 如果当前是编辑
if (this.type === 'edit') {
await updateUserEnterpriseDistributor(this.data)
}
// 关闭弹框
this.handleClose(true)
// 重新刷新列表
this.$emit('refresh')
} catch (error) {
console.error(error)
}
// 关闭loading状态
this.isLoading = false
})
}
}
}
</script>
.rnr-dialog {
.el-dialog__header {
color: #333333;
font-family: PingFangSC-Medium;
font-size: 16px;
font-weight: 500;
padding: 16px 20px;
height: 56px;
}
.el-dialog__body {
font-family: PingFangSC-Regular;
padding: 24px;
.el-form {
.el-form-item {
.el-form-item__label {
color: #71747B;
font-size: 14px;
height: 20px;
font-weight: 400;
line-height: 20px;
margin-bottom: 10px;
}
.el-input__inner {
height: 32px;
line-height: 32px;
}
&:last-child {
margin-bottom: 0;
}
.el-form-item__field-tip {
color: #71747B;
font-size: 12px;
line-height: 16px;
padding-top: 4px;
}
&.is-error {
.el-form-item__field-tip {
display: none;
}
}
}
}
}
.el-dialog__footer {
box-shadow: 0px 0px 12px 0px rgba(196, 198, 207, 0.21);
padding: 16px 24px;
text-align: right;
.el-button {
border-radius: 4px;
height: 32px;
line-height: 32px;
padding: 0 24px;
}
}
.el-row {
margin-top: 24px;
}
}
\ No newline at end of file
<template>
<div v-loading.fullscreen.lock="fullscreenLoading" class="page-management-dealer" element-loading-spinner="page-loading">
<SearchTable
ref="searchTableRef"
v-model="formData"
title="经销商管理"
@reset="handleReset"
@submit="handleSubmit"
>
<template slot="slot-form">
<el-col :span="8">
<el-form-item label="经销商名称" label-width="82px">
<el-input v-model="formData.distributorName" placeholder="请输入经销商名称" />
</el-form-item>
</el-col>
</template>
<template slot="slot-action-bar">
<el-button type="primary" icon="el-icon-plus" @click="handleOpenUpdateDealerDialog('add')">新增经销商</el-button>
</template>
<template slot="slot-table">
<el-table-column prop="distributorName" label="经销商名称" />
<el-table-column prop="distributorAdminUserName" label="管理员姓名" width="160px" />
<el-table-column prop="distributorAdminUserAccount" label="管理员账号" />
<el-table-column prop="phone" label="管理员手机" width="130px" />
<el-table-column prop="createTime" label="时间" sortable width="180px" />
<el-table-column label="状态" width="120px">
<template slot-scope="scope">
<div class="status-wrap">
<i :class="scope.row.status == 0 ? 'red' : 'green'" class="status-point" />
{{ ['未启用', '已启用'][scope.row.status] }}
</div>
</template>
</el-table-column>
<el-table-column label="操作" width="160px" fixed="right">
<template slot-scope="scope">
<div style="white-space: nowrap;">
<!-- <el-button v-if="scope.row.status === 0" type="text" @click="handleUnFreeze(scope.row)">启用</el-button>
<el-button v-if="scope.row.status === 1" type="text" @click="handleFreeze(scope.row)">禁用</el-button>
<span class="separator" /> -->
<el-button type="text" @click="handleOpenUpdateDealerDialog('edit', scope.row)">编辑</el-button>
<span class="separator" />
<el-dropdown @command="command => handleDropDownCommand(command, scope.row)">
<el-button type="text">
更多<i class="el-icon-arrow-down el-icon--right" />
</el-button>
<el-dropdown-menu slot="dropdown" class="ui-dropdown">
<el-dropdown-item command="CHANGE_ADMIN">变更管理员</el-dropdown-item>
<el-dropdown-item command="ACCOUNT_MANAGE">账户管理</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</template>
</el-table-column>
</template>
</SearchTable>
<!-- 添加/编辑经销商 start -->
<UpdateDistributor :visible.sync="updateDealerDialog.show" :type="updateDealerDialog.type" :data="updateDealerDialog.data" @refresh="handleRefresh" />
<!-- 添加编辑经销商 end -->
<!--变更管理员弹框 start -->
<ChangeAdmin :visible.sync="changeAdminDialog.show" :data="changeAdminDialog.data" @refresh="handleRefresh" />
<!-- 变更管理员弹框 end -->
</div>
</template>
<script>
import UpdateDistributor from './components/UpdateDistributor'
import ChangeAdmin from './components/ChangeAdmin'
import SearchTable from '@/components/SearchTable'
import {
queryUserEnterpriseDistributor,
unfreezeUserEnterpriseDistributor,
frozenUserEnterpriseDistributor
} from '@/api/management'
export default {
name: 'DealerManagement',
components: { SearchTable, UpdateDistributor, ChangeAdmin },
data() {
return {
fullscreenLoading: false,
// 弹出框内双向绑定的数据
formData: {
distributorName: ''
},
// 添加或编辑经销商的弹框数据
updateDealerDialog: {
show: false,
type: 'add',
data: {}
},
// 变更管理员弹框
changeAdminDialog: {
show: false,
data: {}
}
}
},
methods: {
/**
* 查询经销商数据
* @param formData 当前接口请求数据
* @param callback 回调方法,渲染页面使用
*/
async handleSubmit(formData, callback) {
// 查询接口数据
const { list, totalCount } = await queryUserEnterpriseDistributor(formData)
// 执行回调方法
callback({ list, totalCount })
},
/**
* 经销商-启用
* @param row 当前行数据
*/
async handleUnFreeze(row) {
// 开始请求接口数据
await unfreezeUserEnterpriseDistributor({ uuid: row.uuid })
// 刷新页面数据
this.handleRefresh()
},
/**
* 经销商-禁用
* @param row 当前行数据
*/
async handleFreeze(row) {
// 开始请求接口数据
await frozenUserEnterpriseDistributor({ uuid: row.uuid })
// 刷新页面数据
this.handleRefresh()
},
/**
* 刷新表格数据
*/
handleRefresh() {
// 重新刷新页面
this.$refs.searchTableRef.handleSubmit()
},
/**
* 打开编辑或新增管理员弹框
* @param type 类型
* @param row 当前行数据
*/
handleOpenUpdateDealerDialog(type = 'edit', row = {}) {
// 更新管理员弹框
this.updateDealerDialog = {
show: true,
type,
data: { ...row }
}
},
/**
* 打开更换管理员弹框
* @param row 当前行数据
*/
handleOpenChangeAdminDialog(row) {
this.changeAdminDialog = {
show: true,
data: row
}
},
/**
* 下拉触发命令
* @param command 当前命令
* @param row 当前行数据
*/
handleDropDownCommand(command, row) {
// 根据命令做操作
switch (command) {
case 'CHANGE_ADMIN':
this.handleOpenChangeAdminDialog(row)
break
case 'ACCOUNT_MANAGE':
this.$router.push({
name: 'UserManagement',
query: {
organId: row.id,
organName: row.distributorName
}
})
break
}
},
/**
* 如果点击重置
*/
handleReset() {
// 重置数据
this.formData.distributorName = ''
// 刷新页面数据
this.handleRefresh()
}
}
}
</script>
<style lang="scss">
.page-management-dealer {
.status-wrap {
align-items: center;
display: flex;
.status-point {
border-radius: 3px;
display: inline-block;
width: 6px;
height: 6px;
margin-right: 8px;
&.green {
background-color: #25C343;
}
&.red {
background-color: #FF4D4F;
}
}
}
.separator {
background: #DCDFE6;
display: inline-block;
width: 1px;
height: 14px;
margin: 0 2px -2px;
}
}
.ui-dropdown {
padding: 4px 8px;
.el-dropdown-menu__item {
color: #2A68FF;
&:hover {
background: rgba(236, 243, 255, 0.5);
border-radius: 2px;
}
}
}
</style>
<template>
<el-dialog
:visible="visible"
:title="`${type === 'add' ? '新增' : '编辑'}子组织`"
:close-on-click-modal="false"
:close-on-press-escape="false"
class="rnr-dialog"
width="960px"
destroy-on-close
@close="$emit('update:visible', false)"
>
<el-form ref="formRef" :model="data" label-position="top">
<el-row :gutter="24">
<el-col :span="12">
<el-form-item :rules="IS_NOT_EMPTY('请输入组织名称')" prop="organName" label="组织名称">
<el-input v-model="data.organName" placeholder="请输入组织名称" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="组织类型" prop="bizType">
<el-select v-model="data.bizType">
<!-- <el-option label="车企" :value="1" /> -->
<el-option label="经销商" :value="2" />
<el-option label="车企子公司" :value="3" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item prop="comment" label="备注">
<el-input v-model="data.comment" placeholder="请输入备注" />
</el-form-item>
</el-col>
<el-col v-if="type === 'add'" :span="12">
<el-form-item :rules="IS_NOT_EMPTY('请输入管理员姓名')" prop="organAdminName" label="管理员姓名">
<el-input v-model="data.organAdminName" placeholder="请输入管理员姓名" />
</el-form-item>
</el-col>
</el-row>
<el-row v-if="type === 'add'" :gutter="24">
<el-col :span="12">
<el-form-item :rules="IS_NOT_EMPTY('请输入管理员账号')" prop="organAdminAccount" label="管理员账号">
<el-input v-model="data.organAdminAccount" placeholder="请输入管理员账号" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item :rules="[IS_NOT_EMPTY('请输入管理员手机号'), IS_PHONE()]" prop="organAdminPhone" label="管理员手机号">
<el-input v-model="data.organAdminPhone" type="number" placeholder="请输入管理员手机号" />
</el-form-item>
</el-col>
</el-row>
<el-row v-if="type === 'add'" :gutter="24">
<el-col :span="12">
<el-form-item :rules="[IS_NOT_EMPTY('请输入管理员密码'), IS_RIGHT_PASSWORD()]" prop="password" label="管理员密码">
<el-input v-model="data.password" :placeholder="type === 'add' ? '请输入管理员密码' : '******'" type="password" />
<div class="el-form-item__field-tip">密码长度必须为8~20位字符,由大写字母、小写字母、数字、特殊符号中的3种及以上类型组成</div>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item :rules="[IS_NOT_EMPTY('请输入确认密码'), CONFIRM_PASSWORD]" prop="confirmPassword" label="确认密码">
<el-input v-model="data.confirmPassword" :placeholder="type === 'add' ? '请确认输入的密码' : '******'" type="password" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="handleClose()">取消</el-button>
<el-button :loading="isLoading" type="primary" @click="handleSubmit">确定</el-button>
</span>
</el-dialog>
</template>
<script>
import { createOrgan, updateOrgan } from '@/api/management'
import { IS_NOT_EMPTY, IS_PHONE, CONFIRM_PASSWORD, IS_RIGHT_PASSWORD } from '../../rules'
export default {
name: 'UpdateOrganization',
props: {
visible: {
type: Boolean,
default: false
},
type: {
type: String,
default: 'add'
},
data: {
type: Object,
default: () => ({})
}
},
data() {
return {
IS_NOT_EMPTY,
IS_PHONE,
IS_RIGHT_PASSWORD,
isLoading: false
}
},
computed: {
/**
* 确认密码
*/
CONFIRM_PASSWORD() {
return CONFIRM_PASSWORD(this.data.password)
}
},
methods: {
/**
* 点击关闭方法
*/
handleClose() {
this.$emit('update:visible', false)
},
/**
* 点击保存方法
*/
handleSubmit() {
// 对输入的数据进行校验
this.$refs.formRef.validate(async valid => {
// 如果校验失败
if (!valid) {
return
}
// 展示loading状态
this.isLoading = true
try {
// 组织管理
const { organId } = this.$route.query
// 更加类型判断是调用新建接口还是编辑接口
const requestFn = this.type === 'add' ? createOrgan : updateOrgan
// 创建组织
await requestFn({
...this.data,
parentId: organId || this.$store.getters.organId
})
// 关闭弹框
this.handleClose(true)
// 重新刷新列表
this.$emit('refresh')
} catch (error) {
console.error(error)
}
// 关闭loading状态
this.isLoading = false
})
}
}
}
</script>
<template>
<div class="page-management-organization">
<SearchTable
title="组织管理"
ref="searchTableRef"
v-model="formData"
@reset="handleClear"
@submit="handleSubmit"
>
<template #slot-form>
<el-col :span="isTablet ? 12 : 6" :style="{ marginBottom: isTablet ? '16px' : '0px' }">
<el-form-item label="所属组织" label-width="82px">
<el-input v-model="formData.parentName" readonly />
</el-form-item>
</el-col>
<el-col :span="isTablet ? 12 : 6" :style="{ marginBottom: isTablet ? '16px' : '0px' }">
<el-form-item label="子组织名称" label-width="82px">
<el-input v-model="formData.organName" placeholder="请输入子组织名称" clearable />
</el-form-item>
</el-col>
</template>
<template #slot-action-bar>
<el-button :disabled="isShowBack" type="primary" icon="el-icon-top" @click="handleBack">返回上级组织</el-button>
<el-button type="primary" icon="el-icon-plus" @click="handleAddOrganization">新增子组织</el-button>
</template>
<template #slot-table>
<el-table-column label="所属组织" prop="parentOrganName" min-width="120px" />
<el-table-column label="子组织名称" prop="organName" min-width="160px" />
<el-table-column label="子组织类型" min-width="140px">
<template slot-scope="scope">
{{ ['', '车厂', '经销商', '车企子组织'][scope.row.bizType] }}
</template>
</el-table-column>
<el-table-column label="管理员姓名" prop="organAdminName" min-width="120px" />
<el-table-column label="管理员账号" prop="organAdminAccount" min-width="140px" />
<el-table-column label="管理员手机" prop="organAdminPhone" min-width="140px" />
<el-table-column label="创建时间" prop="createTime" min-width="160px" />
<el-table-column label="状态" prop="status" min-width="80px">
<template slot-scope="scope">
<div class="status-wrap">
<i :class="scope.row.status == 0 ? 'red' : 'green'" class="status-point" />
{{ ['未启用', '已启用'][scope.row.status] }}
</div>
</template>
</el-table-column>
<el-table-column label="操作" min-width="120px">
<template slot-scope="scope">
<!-- <el-button type="text">禁用</el-button> -->
<el-button type="text" @click="handleEditOrganization(scope.row)">编辑</el-button>
<span class="separator" />
<el-dropdown @command="command => handleDropDownCommand(command, scope.row)">
<el-button type="text">
更多<i class="el-icon-arrow-down el-icon--right" />
</el-button>
<el-dropdown-menu slot="dropdown" class="ui-dropdown">
<el-dropdown-item command="CHANGE_ADMIN">变更管理员</el-dropdown-item>
<el-dropdown-item command="ACCOUNT_MANAGE">账户管理</el-dropdown-item>
<el-dropdown-item command="EDIT_CHILD_ORG">编辑子组织</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template>
</el-table-column>
</template>
</SearchTable>
<!-- 新增或更新管理员 -->
<UpdateOrganization :visible.sync="updateOrgDialog.show" :type="updateOrgDialog.type" :data="updateOrgDialog.data" @refresh="handleRefresh" />
<!--变更管理员弹框 start -->
<ChangeAdmin :visible.sync="changeAdminDialog.show" :data="changeAdminDialog.data" from="organ" @refresh="handleRefresh" />
</div>
</template>
<script>
import cache from '@/utils/cache'
import { queryOrganList } from '@/api/management'
import SearchTable from '@/components/SearchTable'
import UpdateOrganization from './components/UpdateOrganization'
import ChangeAdmin from '../dealer/components/ChangeAdmin'
// 组织下钻时保存的数据列表
const STORAGE_CODE = 'ORGAN_PARENT_LIST'
export default {
name: 'OrganizationManage',
components: { SearchTable, UpdateOrganization, ChangeAdmin },
data() {
return {
formData: {
...this.getOrganFromRoute(),
organName: ''
},
updateOrgDialog: {
show: false,
type: 'add',
data: {}
},
changeAdminDialog: {
show: false,
data: {}
},
isTablet: window.OS.isTablet
}
},
computed: {
/**
* 是否展示返回上一级的目录
*/
isShowBack() {
const { organId } = this.$route.query
// 如果当前没有组织id,则清空缓存
if (!organId) {
cache.remove(STORAGE_CODE)
}
return !organId
}
},
watch: {
'$route'(to, from) {
// 如果当前返回到第一级
if (!to.query.organId) {
this.formData = {
...this.getOrganFromRoute(),
organName: ''
}
}
// 刷新页面
this.$refs.searchTableRef.handleSubmit()
}
},
methods: {
/**
* 点击查询搜索的方法
* @param formData 当前表单数据包括分页
* @param callback 回调方法
*/
async handleSubmit(formData, callback) {
// 开始查询接口返回
const { list, totalCount } = await queryOrganList(formData)
// 回调渲染接口
callback({ list, totalCount })
},
/**
* 清空数据
*/
handleClear() {
this.formData.organName = ''
},
/**
* 刷新数据
*/
handleRefresh() {
this.$refs.searchTableRef.handleSubmit()
},
/**
* 新增组织管理
*/
handleAddOrganization() {
// 开始更新数据
this.$set(this.updateOrgDialog, 'show', true)
this.$set(this.updateOrgDialog, 'type', 'add')
this.$set(this.updateOrgDialog, 'data', { bizType: 2 })
},
/**
* 返回到上一级
*/
handleBack() {
// 获取缓存的数据
const cacheData = cache.get(STORAGE_CODE, [])
// 删除左后一条数据
cacheData.splice(-1)
// 先保存数据
cache.set(
STORAGE_CODE,
cacheData
)
// 跳转页面
this.toOrganRoute(cacheData[cacheData.length - 1])
},
/**
* 编辑组织
* @param row 当前行数据
*/
handleEditOrganization(row) {
// 开始更新数据
this.$set(this.updateOrgDialog, 'show', true)
this.$set(this.updateOrgDialog, 'type', 'edit')
this.$set(this.updateOrgDialog, 'data', { ...row })
},
/**
* 打开更换管理员弹框
* @param row 当前行数据
*/
handleOpenChangeAdminDialog(row) {
this.changeAdminDialog = {
show: true,
data: row
}
},
/**
* 下拉触发命令
* @param command 当前命令
* @param row 当前行数据
*/
handleDropDownCommand(command, row) {
// 根据命令做操作
switch (command) {
case 'CHANGE_ADMIN':
this.handleOpenChangeAdminDialog(row)
break
case 'ACCOUNT_MANAGE':
this.$router.push({
name: 'UserManagement',
query: {
organId: row.uuid,
organName: row.organName
}
})
break
case 'EDIT_CHILD_ORG':
// 先保存数据
cache.set(
STORAGE_CODE,
[
...cache.get(STORAGE_CODE, []),
{
organId: row.uuid,
organName: row.organName
}
]
)
// 跳转页面
this.toOrganRoute({
organId: row.uuid,
organName: row.organName
})
break
}
},
/**
* 获取组织管理信息
*/
getOrganFromRoute() {
// 从路由中获取组织id和组织名称
let { organId, organName } = this.$route.query
// 如果当前没有组织id,则从缓存中取
if (!organId) {
organId = this.$store.getters.organId
organName = this.$store.getters.organName
}
return { parentId: organId, parentName: organName }
},
/**
* 跳转到组织的路由中
* @param query 当前需要携带在路由中的数据
*/
toOrganRoute(query = {}) {
// 组织id和组织名称
const { organId, organName } = this.$store.getters
// 构建表单数据
this.formData = {
...this.formData,
organName: '',
parentId: query.organId || organId,
parentName: query.organName || organName
}
// 跳转页面
this.$router.replace({
name: 'OrganizationManagement',
query
})
}
}
}
</script>
<style lang="scss" scoped>
.page-management-organization {
.status-wrap {
align-items: center;
display: flex;
.status-point {
border-radius: 3px;
display: inline-block;
width: 6px;
height: 6px;
margin-right: 8px;
&.green {
background-color: #25C343;
}
&.red {
background-color: #FF4D4F;
}
}
}
.separator {
background: #DCDFE6;
display: inline-block;
width: 1px;
height: 14px;
margin: 0 2px -2px;
}
}
</style>
/**
* 非空校验
* @param message 错误信息
*/
export const IS_NOT_EMPTY = (message, trigger = 'blur') => ({
required: true,
trigger,
message
})
/**
* 当前是手机号
*/
export const IS_PHONE = _ => ({
// 当前是否是手机号
validator: (rule, value, callback) => {
if (/1\d{10}/.test(value)) {
callback()
} else {
callback(new Error('请输入正确的手机号'))
}
},
trigger: 'blur'
})
/**
* 确认密码输入是否正确
* @param password 当前输入的密码
*/
export const CONFIRM_PASSWORD = password => ({
validator: (rule, value, callback) => {
// 如果输入值不一样
if (value && password !== value) {
callback(new Error('两次输入密码不一致!'))
} else {
callback()
}
},
trigger: 'blur'
})
/**
* 是否是合法的密码
*/
export const IS_RIGHT_PASSWORD = _ => ({
validator: (rule, password, callback) => {
// 如果输入的密码格式不正确
if (password && !/^(?=.*[0-9])(?=.*[a-zA-Z])(?=.*[^a-zA-Z0-9]).{8,}$/.test(`${password}`)) {
callback(new Error('密码需包含大小写字母,数字及特殊字符'))
} else {
callback()
}
}
})
<template>
<div v-loading.fullscreen.lock="fullscreenLoading" element-loading-spinner="page-loading" class="app-container">
<page-title />
<div class="search-form">
<el-form ref="formRef" :model="formData" label-position="left" label-width="70px">
<el-row :gutter="20">
<el-col :span="4">
<el-form-item label="所属组织">
<el-select v-model="formData.companyNo" disabled>
<el-option label="组织1" value="1" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="姓名">
<el-input v-model="formData.username" />
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="用户名">
<el-input v-model="formData.nickname" />
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="手机号">
<el-input v-model="formData.phone" />
</el-form-item>
</el-col>
<el-col :span="5">
<el-button round size="small" type="primary" icon="iconfont icon-search">搜索</el-button>
<el-button round size="small" type="gray" icon="iconfont icon-clear">清除</el-button>
<el-button round size="small" type="primary" icon="el-icon-circle-plus-outline" @click="handleAdd()">新增</el-button>
</el-col>
</el-row>
</el-form>
</div>
<div class="table-list">
<el-table ref="tableRender" :data="list">
<el-table-column prop="username" label="姓名" />
<el-table-column prop="account" label="账户" />
<el-table-column prop="phone" label="手机号" />
<el-table-column prop="nickname" label="昵称" />
<el-table-column prop="role" label="角色" />
<el-table-column prop="status" label="用户状态" />
<el-table-column prop="company" label="所属组织" />
<el-table-column label="操作" width="200px">
<template slot-scope="scope">
<el-button type="text" @click="handleEdit(scope.row)">编辑</el-button>
<el-button type="text" @click="handleDetails(scope.row)">详情</el-button>
<el-button type="text" @click="handleResetPassword(scope.row)">重置密码</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
:page-sizes="[20, 50, 100, 200, 300]"
:page-size="20"
:total="1"
:current-page="1"
layout="total, sizes, prev, pager, next, jumper"
/>
</div>
<!-- 操作用户弹窗 start -->
<userOperationDialog :visible="visible" :dialog-title="dialogTitle" :form-data="currentRow" :operation-mode="operationMode" @updateVisible="updateVisible"/>
<!-- 操作用户弹窗 end -->
</div>
</template>
<script>
import userOperationDialog from './userOperation.vue'
export default {
name: 'BaseManagement',
components: { userOperationDialog },
data() {
return {
fullscreenLoading: false,
list: [
{ username: '张三', account: '11', phone: '17625907745', nickname: '张三不散', role: 'admin', status: '启用', company: '宝马' }
],
formData: {},
pagination: {
total: 0,
currentPage: 1,
pageSize: 20
},
visible: false,
dialogTitle: '',
currentRow: {},
operationMode: ''
}
},
methods: {
/**
* 新增
*/
handleAdd() {
this.visible = true
this.operationMode = 'add'
},
/**
* 编辑
*/
handleEdit(row) {
this.currentRow = row
this.visible = true
this.operationMode = 'edit'
},
/**
* 详情
*/
handleDetails(row) {
this.currentRow = row
this.visible = true
this.operationMode = 'details'
},
/**
* 重置密码
*/
handleResetPassword(row) {
this.currentRow = row
this.visible = true
this.operationMode = 'add'
},
/**
* 关闭弹窗
*/
updateVisible(val) {
this.visible = val
}
}
}
</script>
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment