提交 5ecec6e8 authored 作者: 王鹏飞's avatar 王鹏飞

v2

上级 e4f540e7
<template> <template>
<div id="app"> <div id="app">
<vue-form <vue-form
asideWidth="295px"
:menus="menus" :menus="menus"
@change="handleChange" @change="handleChange"
@success="handleSuccess" @success="handleSuccess"
...@@ -13,8 +12,8 @@ ...@@ -13,8 +12,8 @@
<table border="1"> <table border="1">
<template v-for="(item, index) in submenu"> <template v-for="(item, index) in submenu">
<tr :key="index" v-if="index < 7"> <tr :key="index" v-if="index < 7">
<td>{{index}}{{item.title}}</td> <td>{{ index }}{{ item.title }}</td>
<td>{{item.progress ? '已完成' : '未完成'}}</td> <td>{{ item.progress ? '已完成' : '未完成' }}</td>
</tr> </tr>
</template> </template>
</table> </table>
...@@ -24,8 +23,8 @@ ...@@ -24,8 +23,8 @@
</template> </template>
<script> <script>
import axios from 'axios' import axios from 'axios'
import kelleyForm from './kelley-form' // import kelleyForm from './kelley-form'
import sofiaForm from './sofia-form' // import sofiaForm from './sofia-form'
function url2Json(url) { function url2Json(url) {
const str = url.split('?').pop() const str = url.split('?').pop()
...@@ -40,51 +39,55 @@ const projectId = query.projectId || '1000' ...@@ -40,51 +39,55 @@ const projectId = query.projectId || '1000'
const menus = [ const menus = [
{ {
id: 'center', id: '0',
title: '报名中心' title: '报名申请',
},
{
id: 'entry',
title: '办理入学',
isGroup: true,
children: [ children: [
{ {
id: 'entry_required', id: '0-0',
title: '必填项', title: '个人资料',
children: [ tabs: [
{ {
id: 'entry_protocol', id: '1',
title: '入学协议', title: '个人资料',
showProgress: true, required: true,
progress: 0 form: {}
}, },
{ {
id: 'entry_payment', id: '2',
title: '缴费凭证', title: '教育背景',
showProgress: true, required: true,
progress: 0 form: {}
}
]
}
]
}, },
{ {
id: 'user', id: '3',
title: '个人信息', title: '工作经验',
children: [ required: true,
form: {}
},
{
id: '4',
title: '学习目的',
required: true,
form: {}
},
{ {
id: 'user_info', id: '5',
title: '个人信息修改' title: '所受培训',
form: {}
}, },
{ {
id: 'user_password', id: '6',
title: '密码修改' title: '荣誉奖励',
form: {}
} }
] ]
}, },
{ {
id: 'download', id: '0-1',
title: '相关下载' title: '推荐信',
form: {}
}
]
} }
] ]
...@@ -94,7 +97,8 @@ export default { ...@@ -94,7 +97,8 @@ export default {
return { return {
projectId, projectId,
currentActive: query.active || 'download', currentActive: query.active || 'download',
menus: projectId === '1000' ? [...sofiaForm, ...menus] : kelleyForm menus
// menus: projectId === '1000' ? [...sofiaForm, ...menus] : kelleyForm
} }
}, },
computed: { computed: {
...@@ -116,14 +120,13 @@ export default { ...@@ -116,14 +120,13 @@ export default {
}, },
// 获取进度 // 获取进度
getProgress() { getProgress() {
axios axios.get(`/zws/v1/enrollment/submissions?project_id=${this.projectId}`).then(response => {
.get(`/zws/v1/enrollment/submissions?project_id=${this.projectId}`)
.then(response => {
let children = this.menus[0].children let children = this.menus[0].children
const submitProgress = response.data.submit_progress const submitProgress = response.data.submit_progress
children.forEach(item => { children.forEach(item => {
let progress = 0 let progress = 0
if (submitProgress.hasOwnProperty(item.id)) { console.log(submitProgress)
if (Object.prototype.hasOwnProperty.call(submitProgress, item.id)) {
progress = submitProgress[item.id] === 0.2 ? 100 : 0 progress = submitProgress[item.id] === 0.2 ? 100 : 0
} }
item.progress = progress item.progress = progress
...@@ -132,7 +135,7 @@ export default { ...@@ -132,7 +135,7 @@ export default {
} }
}, },
beforeMount() { beforeMount() {
this.getProgress() // this.getProgress()
} }
} }
</script> </script>
...@@ -142,4 +145,7 @@ export default { ...@@ -142,4 +145,7 @@ export default {
margin: 0; margin: 0;
padding: 0; padding: 0;
} }
body {
background: #f5f6fa;
}
</style> </style>
<template>
<div id="app">
<vue-form
:menus="menus"
@change="handleChange"
@success="handleSuccess"
@error="handleError"
:default-active="currentActive"
>
</vue-form>
</div>
</template>
<script>
import axios from 'axios'
import { Message } from 'element-ui'
// 报名申请
import application from './application'
// 申请面试
import interview from './interview'
// 入学办理
import admission from './admission'
const menus = [application, interview, admission]
export default {
name: 'app',
data() {
return {
projectId: '1005',
currentActive: 'application_info',
menus
}
},
computed: {
submenu() {
return this.menus[0].children
}
},
methods: {
handleChange(value) {
this.currentActive = value
console.log('页面切换了', value)
},
handleSuccess(data) {
console.log('提交成功了', data)
Message({ type: 'success', message: data.message })
// this.getProgress()
},
handleError(data) {
console.log('提交失败了', data)
Message({ type: 'error', message: data.message })
},
// 获取进度
getProgress() {
axios.get(`/zws/v1/enrollment/submissions?project_id=${this.projectId}`).then(response => {
let children = this.menus[0].children
const submitProgress = response.data.submit_progress
children.forEach(item => {
let progress = 0
console.log(submitProgress)
if (Object.prototype.hasOwnProperty.call(submitProgress, item.id)) {
progress = submitProgress[item.id] === 0.2 ? 100 : 0
}
item.progress = progress
})
})
}
},
beforeMount() {
// this.getProgress()
}
}
</script>
<style lang="scss">
* {
margin: 0;
padding: 0;
}
body {
background: #f5f6fa;
}
#app {
width: 1000px;
margin: 40px auto;
}
</style>
import xy from './xy'
import xfjn from './xfjn'
export default {
id: 'admission',
title: '入学办理',
children: [xy, xfjn]
}
export default {
id: 'admission_xfjn',
title: '学费缴纳',
html: `
<p><strong>一、对公收款银行信息:</strong></p>
<p>户名:清控紫荆( 北京)教育科技股份有限公司</p>
<p>帐号:694485289</p>
<p>开户行:中国民生银行股份有限公司北京魏公村支行</p>
<p style="margin-top:30px;"><strong>二、支付宝收款账户信息:</strong></p>
<p>支付宝账号:service@ezijing.com</p>
<p>支付宝户名:清控紫荆(北京)教育科技股份有限公司</p>
`
}
export default {
id: 'admission_xy',
title: '入学协议',
get: {
action: '/v1.0/application-materials/1005',
callback(data) {
const { attachments = [] } = data.data.material
const filelist = attachments.filter(item => {
return item.file_type_id === 'ADMISSION_AGREEMENT'
})
return { filelist }
}
},
form: {
hasButton: false,
options: {},
items: [
{
type: 'v-upload',
required: true,
model: 'filelist',
attrs: {
action: '/v1.0/application-materials/attachments/1005/put',
deleteAction: '/v1.0/application-materials/attachments/1005/delete',
data: { file_type: 'ADMISSION_AGREEMENT' }
},
prepend: '2寸照片:以电子版的形式上传文件',
append: '注意事项:需要将证书原件扫描或拍照后提交,请确保证书内容清晰可辨。'
}
]
}
}
/**
* 申请申明
*/
export default {
id: 'application_declare',
title: '申请申明',
update: {
action: '/v1.0/application-materials/submit/1005'
},
form: {
model: { isAgree: [] },
items: [
{
type: 'v-checkbox',
values: [{ label: '同意', value: 1 }],
model: 'isAgree',
rules: [{ required: true, message: '请阅读协议', trigger: 'change' }],
prepend: `<p>我提供的所有报名材料信息皆准确和完整。我同意在需要的情况下提交原件以确认我的报名资格。由于报名材料中的虚假、错误信息或重大遗漏导致不录取或取消学籍的后果由我个人承担。 我理解并同意所有报名材料归紫荆教育所有,无论考生录取与否均不退回。我授权紫荆教育使用报名表中的信息查询本人学习和工作记录。</p>`
}
]
}
}
import info from './info'
import tjx from './tjx'
import wfzsm from './wfzzm'
import declare from './declare'
export default {
id: 'application',
title: '报名申请',
children: [info, tjx, wfzsm, declare, { id: 'application_pay', title: '缴报名费' }]
}
// import first from './info/first'
import profile from './info/profile'
import education from './info/education'
import career from './info/career'
import honor from './info/honor'
import training from './info/training'
import answer from './info/answer'
export default {
id: 'application_info',
title: '个人资料',
tabs: [profile, education, career, answer, training, honor]
}
/**
* 学习目的
*/
export default {
id: 'application_info_answer',
title: '学习目的',
required: true,
get: {
action: '/v1.0/application-materials/1005',
callback(data) {
const { answers = [] } = data.data.material
let [first = {}, second = {}] = answers
return {
qid1: first.qid || '1',
question1:
first.question || '您为什么要申请美国印第安纳大学Kelley商学院金融学硕士项目?(200字以上,1000字以内)',
answer1: first.answer,
qid2: second.qid || '2',
question2:
second.question || '您的短期和长期职业发展目标是什么?您打算如何达成此愿景?(200字以上,1000字以内)',
answer2: second.answer
}
}
},
update: {
action: '/v1.0/application-materials/1005/put',
beforeRequest(data) {
return {
answers: [
{ qid: data.qid1, question: data.question1, answer: data.answer1 },
{ qid: data.qid2, question: data.question2, answer: data.answer2 }
]
}
}
},
form: {
items: [
{
type: 'v-input',
label: '个人描述(60-1000字)中文或者英文',
model: 'answer1',
attrs: { type: 'textarea', rows: '8', maxlength: '1000', style: 'width:100%' },
rules: [
{ required: true, message: '请输入', trigger: 'blur' },
{ min: 200, max: 1000, message: '长度在 200 到 1000 个字符', trigger: 'blur' }
]
},
{
type: 'v-input',
label: '申请紫荆教育康博斯威尔大学教育硕士的原因?以及您的职业或个人发展的预期目标(60-1000字)中文或者英文',
model: 'answer2',
attrs: { type: 'textarea', rows: '8', maxlength: '1000', style: 'width:100%' },
rules: [
{ required: true, message: '请输入', trigger: 'blur' },
{ min: 200, max: 1000, message: '长度在 200 到 1000 个字符', trigger: 'blur' }
]
}
]
}
}
/**
* 工作经验
*/
export default {
id: 'application_info_career',
title: '工作经验',
required: true,
get: {
action: '/v1.0/application-materials/1005',
callback(data) {
const { careers = [] } = data.data.material
return careers.map(item => {
const { start_date: startDate, end_date: endDate } = item
if (startDate) {
item.dates = [startDate, endDate]
}
return item
})
}
},
update: {
action: '/v1.0/application-materials/1005/put',
beforeRequest(data) {
const careers = data.map(item => {
let [startDate, endDate] = item.dates
item.start_date = startDate
item.end_date = endDate
return [
'start_date',
'end_date',
'company_name_cn',
'industry',
'dept_cn',
'position_cn',
'job_desc_cn'
].reduce((result, key) => {
result[key] = item[key]
return result
}, {})
})
return { careers }
}
},
form: {
hasAdd: true,
options: {
labelWidth: '140px'
},
items: [
{
type: 'v-datepicker',
label: '工作时间',
model: 'dates',
attrs: {
type: 'monthrange',
rangeSeparator: '至',
startPlaceholder: '请选择开始时间',
endPlaceholder: '请选择结束时间',
valueFormat: 'yyyyMM'
},
rules: [{ required: true, message: '请选择教育时间', trigger: 'blur' }]
},
{
type: 'v-input',
label: '工作单位',
model: 'company_name_cn',
attrs: { placeholder: '请输入工作单位' },
rules: [{ required: true, message: '请输入工作单位', trigger: 'blur' }]
},
{
type: 'v-select',
values: [
{ label: '互联网/电子商务', value: '1 ' },
{ label: '基金/证券/期货/投资', value: '2 ' },
{ label: '保险', value: '3 ' },
{ label: '银行', value: '4 ' },
{ label: '信托/担保/拍卖/典当', value: '5 ' },
{ label: '计算机软件', value: '6 ' },
{ label: 'IT服务(系统/数据/维护)', value: '7 ' },
{ label: '电子技术/半导体/集成电路', value: '8 ' },
{ label: '计算机硬件', value: '9 ' },
{ label: '通信/电信/网络设备', value: '10' },
{ label: '通信/电信运营、增值服务', value: '11' },
{ label: '网络游戏', value: '12' },
{ label: '房地产/建筑/建材/工程', value: '13' },
{ label: '家居/室内设计/装饰装潢', value: '14' },
{ label: '物业管理/商业中心', value: '15' },
{ label: '专业服务/咨询(财会/法律/人力资源等)', value: '16' },
{ label: '广告/会展/公关', value: '17' },
{ label: '中介服务', value: '18' },
{ label: '检验/检测/认证', value: '19' },
{ label: '外包服务', value: '20' },
{ label: '快速消费品(食品/饮料/烟酒/日化)', value: '21' },
{ label: '耐用消费品(服饰/纺织/皮革/家具/家电)', value: '22' },
{ label: '贸易/进出口', value: '23' },
{ label: '零售/批发', value: '24' },
{ label: '租赁服务', value: '25' },
{ label: '教育/培训/院校', value: '26' },
{ label: '礼品/玩具/工艺美术/收藏品/奢侈品', value: '27' },
{ label: '汽车/摩托车', value: '28' },
{ label: '大型设备/机电设备/重工业', value: '29' },
{ label: '加工制造(原料加工/模具)', value: '30' },
{ label: '仪器仪表及工业自动化', value: '31' },
{ label: '印刷/包装/造纸', value: '32' },
{ label: '办公用品及设备', value: '33' },
{ label: '医药/生物工程', value: '34' },
{ label: '医疗设备/器械', value: '35' },
{ label: '航空/航天研究与制造', value: '36' },
{ label: '交通/运输,物流/仓储', value: '37' },
{ label: '医疗/护理/美容/保健/卫生服务', value: '38' },
{ label: '酒店/餐饮,旅游/度假,媒体/出版/影视/文化传播', value: '39' },
{ label: '娱乐/体育/休闲', value: '40' },
{ label: '能源/矿产/采掘/冶炼', value: '41' },
{ label: '石油/石化/化工,电气/电力/水利', value: '42' },
{ label: '环保', value: '43' },
{ label: '政府/公共事业/非盈利机构', value: '44' },
{ label: '学术/科研,农/林/牧/渔跨领域经营', value: '45' },
{ label: '其他', value: '90' }
],
label: '行业类别',
model: 'industry',
rules: [{ required: true, message: '请选择行业类别', trigger: 'change' }]
},
{
type: 'v-input',
label: '工作部门',
model: 'dept_cn',
attrs: { placeholder: '请输入工作部门' },
rules: [{ required: true, message: '请输入工作部门', trigger: 'blur' }]
},
{
type: 'v-input',
label: '工作职位',
model: 'position_cn',
attrs: { placeholder: '请输入工作职位' },
rules: [{ required: true, message: '请输入工作职位', trigger: 'blur' }]
},
{
type: 'v-input',
label: '工作描述',
model: 'job_desc_cn',
attrs: {
type: 'textarea',
placeholder: '请输入工作描述',
rows: '8',
maxlength: '3000'
},
rules: [{ required: true, message: '请输入工作描述', trigger: 'blur' }]
}
]
}
}
/**
* 教育背景
*/
export default {
id: 'application_info_education',
title: '教育背景',
required: true,
get: {
action: '/v1.0/application-materials/1005',
callback(data) {
const { educations = [] } = data.data.material
return educations.map(item => {
const { start_date: startDate, end_date: endDate } = item
if (startDate) {
item.dates = [startDate, endDate]
}
return item
})
}
},
update: {
action: '/v1.0/application-materials/1005/put',
beforeRequest(data) {
const educations = data.map(item => {
let [startDate, endDate] = item.dates
item.start_date = startDate
item.end_date = endDate
return [
'start_date',
'end_date',
'school_name_cn',
'school_country',
'school_city',
'major_cn',
'degree'
].reduce((result, key) => {
result[key] = item[key]
return result
}, {})
})
return { educations }
}
},
form: {
hasAdd: true,
options: {
labelWidth: '140px'
},
items: [
{
type: 'v-datepicker',
label: '教育时间',
model: 'dates',
attrs: {
type: 'monthrange',
rangeSeparator: '至',
startPlaceholder: '请选择开始时间',
endPlaceholder: '请选择结束时间',
valueFormat: 'yyyyMM'
},
rules: [{ required: true, message: '请选择教育时间', trigger: 'blur' }]
},
{
type: 'v-input',
label: '学校名称',
model: 'school_name_cn',
rules: [{ required: true, message: '请输入学校名称', trigger: 'blur' }]
},
{
type: 'v-input',
label: '专业名称',
model: 'major_cn',
rules: [{ required: true, message: '请输入专业名称', trigger: 'blur' }]
},
{
type: 'v-select',
values: [
{ value: '专科' },
{ value: '本科' },
{ value: '本科/学士' },
{ value: '硕士研究生' },
{ value: '研究生/硕士' },
{ value: '博士研究生' },
{ value: '研究生/博士' },
{ value: '其他' }
],
label: '学历/学位',
model: 'degree',
rules: [{ required: true, message: '请选择学历/学位', trigger: 'change' }]
}
]
}
}
/**
* 个人信息
*/
export default {
id: 'application_info_first',
title: '个人信息',
required: true,
get: {
action: '/v1.0/application-materials/1005',
callback(data) {
const { basic_info = {}, attachments = [] } = data.data.material
const attachment = attachments.reduce(
(result, item) => {
const types = ['ID_CARD_FRONT', 'ID_CARD_BACK', 'HK_ID_CARD', 'PASSPORT', 'OTHER_ID_CARD_PHOTO']
types.forEach(type => {
if (item.file_type_id === type) {
result[type].push(item)
}
})
return result
},
{ ID_CARD_FRONT: [], ID_CARD_BACK: [], HK_ID_CARD: [], PASSPORT: [], OTHER_ID_CARD_PHOTO: [] }
)
return Object.assign({}, basic_info, attachment)
}
},
update: {
action: '/v1.0/application-materials/1005/put',
beforeRequest(data) {
const basic_info = ['phone_number', 'email', 'id_type'].reduce((result, key) => {
result[key] = data[key]
return result
}, {})
return { basic_info }
}
},
form: {
// hasButton: false,
options: {
labelWidth: '140px'
},
items: [
{
type: 'v-input',
label: '手机号',
model: 'phone_number',
attrs: { placeholder: '请输入手机号' },
rules: [{ required: true, message: '请输入手机号', trigger: 'blur' }]
},
{
type: 'v-input',
label: '邮箱',
model: 'email',
attrs: { placeholder: '请输入邮箱' },
rules: [{ required: true, message: '请输入邮箱', trigger: 'blur' }]
},
{
type: 'v-select',
values: [{ value: '居民身份证' }, { value: '港澳台身份证' }, { value: '护照' }, { value: '其他' }],
label: '证件类型',
model: 'id_type',
attrs: { placeholder: '请选择证件类型' },
rules: [{ required: true, message: '请选择证件类型', trigger: 'change' }]
},
// 身份证照片(正面)
{
type: 'v-upload',
label: '身份证照片(正面)',
model: 'ID_CARD_FRONT',
attrs: {
action: '/v1.0/application-materials/attachments/1005/put',
deleteAction: '/v1.0/application-materials/attachments/1005/delete',
data: { file_type: 'ID_CARD_FRONT' },
limit: 1
},
rules: [{ type: 'array', required: true, message: '请上传身份证照片(正面)', trigger: 'change' }],
isShow(data) {
return data.id_type === '居民身份证'
}
},
// 身份证照片(背面)
{
type: 'v-upload',
label: '身份证照片(背面)',
model: 'ID_CARD_BACK',
attrs: {
action: '/v1.0/application-materials/attachments/1005/put',
deleteAction: '/v1.0/application-materials/attachments/1005/delete',
data: { file_type: 'ID_CARD_BACK' },
limit: 1
},
rules: [{ type: 'array', required: true, message: '请上传身份证照片(背面)', trigger: 'change' }],
isShow(data) {
return data.id_type === '居民身份证'
}
},
// 港澳台身份证
{
type: 'v-upload',
label: '港澳台身份证',
model: 'HK_ID_CARD',
attrs: {
action: '/v1.0/application-materials/attachments/1005/put',
deleteAction: '/v1.0/application-materials/attachments/1005/delete',
data: { file_type: 'HK_ID_CARD' },
limit: 1
},
rules: [{ type: 'array', required: true, message: '请上传港澳台身份证', trigger: 'change' }],
isShow(data) {
return data.id_type === '港澳台身份证'
}
},
// 护照
{
type: 'v-upload',
label: '护照',
model: 'PASSPORT',
attrs: {
action: '/v1.0/application-materials/attachments/1005/put',
deleteAction: '/v1.0/application-materials/attachments/1005/delete',
data: { file_type: 'PASSPORT' },
limit: 1
},
rules: [{ type: 'array', required: true, message: '请上传护照', trigger: 'change' }],
isShow(data) {
return data.id_type === '护照'
}
},
// 其他证件
{
type: 'v-upload',
label: '其他证件',
model: 'OTHER_ID_CARD_PHOTO',
attrs: {
action: '/v1.0/application-materials/attachments/1005/put',
deleteAction: '/v1.0/application-materials/attachments/1005/delete',
data: { file_type: 'OTHER_ID_CARD_PHOTO' },
limit: 1
},
rules: [{ type: 'array', required: true, message: '请上传其他证件', trigger: 'change' }],
isShow(data) {
return data.id_type === '其他'
}
}
]
}
}
/**
* 荣誉奖励
*/
export default {
id: 'application_info_honor',
title: '荣誉奖励',
get: {
action: '/v1.0/application-materials/1005',
callback(data) {
const { honors = [] } = data.data.material
return honors
}
},
update: {
action: '/v1.0/application-materials/1005/put',
beforeRequest(data) {
const honors = data.map(item => {
return ['time', 'title', 'institution_cn'].reduce((result, key) => {
result[key] = item[key]
return result
}, {})
})
return { honors }
}
},
form: {
hasAdd: true,
options: {
labelWidth: '140px'
},
items: [
{
type: 'v-datepicker',
label: '获取时间',
model: 'time',
attrs: { type: 'date', valueFormat: 'yyyy-MM-dd', placeholder: '请选择获取时间' },
rules: [{ required: true, message: '请选择获取时间', trigger: 'blur' }]
},
{
type: 'v-input',
label: '荣誉奖励',
model: 'title',
attrs: { placeholder: '请输入荣誉奖励' },
rules: [{ required: true, message: '请输入荣誉奖励', trigger: 'blur' }]
},
{
type: 'v-input',
label: '证书颁发机构',
model: 'institution_cn',
rules: [{ required: true, message: '请输入证书颁发机构', trigger: 'blur' }]
}
]
}
}
/**
* 个人信息
*/
export default {
id: 'application_info_profile',
title: '个人信息',
required: true,
get: {
action: '/v1.0/application-materials/1005',
callback(data) {
const { basic_info = {}, attachments = [] } = data.data.material
const attachment = attachments.reduce(
(result, item) => {
const types = ['ID_CARD_FRONT', 'ID_CARD_BACK', 'HK_ID_CARD', 'PASSPORT', 'OTHER_ID_CARD_PHOTO']
types.forEach(type => {
if (item.file_type_id === type) {
result[type].push(item)
}
})
return result
},
{ ID_CARD_FRONT: [], ID_CARD_BACK: [], HK_ID_CARD: [], PASSPORT: [], OTHER_ID_CARD_PHOTO: [] }
)
return Object.assign({}, basic_info, attachment)
}
},
update: {
action: '/v1.0/application-materials/1005/put',
beforeRequest(data) {
// let [province, city] = data.city.split('-')
// data.address_province = province
// data.address_city = city
const basic_info = [
'phone_number',
'email',
'id_type',
'id_number',
'real_name_cn',
'gender',
'nationality',
'birthday',
'address_province',
'address_city',
'we_chat_account',
'mailing_address',
'emergency_contact_name',
'emergency_contacts_phone'
].reduce((result, key) => {
result[key] = data[key]
return result
}, {})
return { basic_info }
}
},
form: {
options: {
labelWidth: '140px'
},
items: [
{
type: 'v-input',
label: '手机号',
model: 'phone_number',
attrs: { disabled: false, placeholder: '请输入手机号' },
rules: [{ required: true, message: '请输入手机号', trigger: 'blur' }]
},
{
type: 'v-input',
label: '邮箱',
model: 'email',
attrs: { disabled: false, placeholder: '请输入邮箱' },
rules: [{ required: true, message: '请输入邮箱', trigger: 'blur' }],
hint: '(后续报名信息将发送至此邮箱,请认真填写)'
},
{
type: 'v-select',
values: [{ value: '居民身份证' }, { value: '港澳台身份证' }, { value: '护照' }, { value: '其他' }],
label: '证件类型',
model: 'id_type',
attrs: { disabled: false, placeholder: '请选择证件类型' },
rules: [{ required: true, message: '请选择证件类型', trigger: 'change' }]
},
// 身份证照片(正面)
{
type: 'v-upload',
label: '身份证照片(正面)',
model: 'ID_CARD_FRONT',
attrs: {
action: '/v1.0/application-materials/attachments/1005/put',
deleteAction: '/v1.0/application-materials/attachments/1005/delete',
data: { file_type: 'ID_CARD_FRONT' },
limit: 1
},
rules: [{ type: 'array', required: true, message: '请上传身份证照片(正面)', trigger: 'change' }],
isShow(data) {
return data.id_type === '居民身份证'
}
},
// 身份证照片(背面)
{
type: 'v-upload',
label: '身份证照片(背面)',
model: 'ID_CARD_BACK',
attrs: {
action: '/v1.0/application-materials/attachments/1005/put',
deleteAction: '/v1.0/application-materials/attachments/1005/delete',
data: { file_type: 'ID_CARD_BACK' },
limit: 1
},
rules: [{ type: 'array', required: true, message: '请上传身份证照片(背面)', trigger: 'change' }],
isShow(data) {
return data.id_type === '居民身份证'
}
},
// 港澳台身份证
{
type: 'v-upload',
label: '港澳台身份证',
model: 'HK_ID_CARD',
attrs: {
action: '/v1.0/application-materials/attachments/1005/put',
deleteAction: '/v1.0/application-materials/attachments/1005/delete',
data: { file_type: 'HK_ID_CARD' },
limit: 1
},
rules: [{ type: 'array', required: true, message: '请上传港澳台身份证', trigger: 'change' }],
isShow(data) {
return data.id_type === '港澳台身份证'
}
},
// 护照
{
type: 'v-upload',
label: '护照',
model: 'PASSPORT',
attrs: {
action: '/v1.0/application-materials/attachments/1005/put',
deleteAction: '/v1.0/application-materials/attachments/1005/delete',
data: { file_type: 'PASSPORT' },
limit: 1
},
rules: [{ type: 'array', required: true, message: '请上传护照', trigger: 'change' }],
isShow(data) {
return data.id_type === '护照'
}
},
// 其他证件
{
type: 'v-upload',
label: '其他证件',
model: 'OTHER_ID_CARD_PHOTO',
attrs: {
action: '/v1.0/application-materials/attachments/1005/put',
deleteAction: '/v1.0/application-materials/attachments/1005/delete',
data: { file_type: 'OTHER_ID_CARD_PHOTO' },
limit: 1
},
rules: [{ type: 'array', required: true, message: '请上传其他证件', trigger: 'change' }],
isShow(data) {
return data.id_type === '其他'
}
},
{
type: 'v-input',
label: '证件号码',
model: 'id_number',
attrs: { disabled: false, placeholder: '请输入证件号码' },
rules: [{ required: true, message: '请输入证件号码', trigger: 'blur' }]
},
{
type: 'v-input',
label: '姓名',
model: 'real_name_cn',
attrs: { placeholder: '请输入姓名' },
rules: [{ required: true, message: '请输入姓名', trigger: 'blur' }]
},
{
type: 'v-radio',
values: [
{ label: '男', value: '男' },
{ label: '女', value: '女' }
],
label: '性别',
model: 'gender',
rules: [{ required: true, message: '请选择性别', trigger: 'change' }]
},
{
type: 'v-input',
label: '国籍',
model: 'nationality',
attrs: { placeholder: '请输入国籍' },
rules: [{ required: true, message: '请输入国籍', trigger: 'blur' }]
},
{
type: 'v-datepicker',
label: '出生日期',
model: 'birthday',
attrs: { type: 'date', placeholder: '请选择出生日期', valueFormat: 'yyyy-MM-dd' },
rules: [{ required: true, message: '请选择出生日期', trigger: 'blur' }]
},
{
type: 'v-input',
label: '居住省',
model: 'address_province',
attrs: { placeholder: '请输入居住省' },
rules: [{ required: true, message: '请输入居住省', trigger: 'blur' }]
},
{
type: 'v-input',
label: '居住市',
model: 'address_city',
attrs: { placeholder: '请输入居住市' },
rules: [{ required: true, message: '请输入居住市', trigger: 'blur' }]
},
// {
// type: 'city-v-select',
// label: '现居住城市',
// model: 'city',
// separator: '-',
// rules: [{ required: true, message: '请选择居住城市', trigger: 'blur' }]
// },
{
type: 'v-input',
label: '微信号',
model: 'we_chat_account',
attrs: { placeholder: '请输入微信号' },
rules: [{ required: true, message: '请输入微信号', trigger: 'blur' }]
},
{
type: 'v-input',
label: '邮寄地址',
model: 'mailing_address',
attrs: { placeholder: '请输入邮寄地址' },
rules: [{ required: true, message: '请输入邮寄地址', trigger: 'blur' }]
},
{
type: 'v-input',
label: '紧急联系人',
model: 'emergency_contact_name',
attrs: { placeholder: '请输入紧急联系人' },
rules: [{ required: true, message: '请输入紧急联系人', trigger: 'blur' }]
},
{
type: 'v-input',
label: '紧急联系电话',
model: 'emergency_contacts_phone',
attrs: { placeholder: '请输入紧急联系电话' },
rules: [{ required: true, message: '请输入紧急联系电话', trigger: 'blur' }]
}
]
}
}
/**
* 所受培训
*/
export default {
id: 'application_info_training',
title: '所受培训',
get: {
action: '/v1.0/application-materials/1005',
callback(data) {
const { trainings = [] } = data.data.material
return trainings.map(item => {
const { start_date: startDate, end_date: endDate } = item
if (startDate) {
item.dates = [startDate, endDate]
}
return item
})
}
},
update: {
action: '/v1.0/application-materials/1005/put',
beforeRequest(data) {
const trainings = data.map(item => {
let [startDate, endDate] = item.dates
item.start_date = startDate
item.end_date = endDate
return ['start_date', 'end_date', 'institution_cn', 'course_cn'].reduce((result, key) => {
result[key] = item[key]
return result
}, {})
})
return { trainings }
}
},
form: {
hasAdd: true,
options: {
labelWidth: '140px'
},
items: [
{
type: 'v-datepicker',
label: '培训时间',
model: 'dates',
attrs: {
type: 'monthrange',
rangeSeparator: '至',
startPlaceholder: '请选择开始时间',
endPlaceholder: '请选择结束时间',
valueFormat: 'yyyyMM'
},
rules: [{ required: true, message: '请选择培训时间', trigger: 'blur' }]
},
{
type: 'v-input',
label: '培训机构',
model: 'institution_cn',
rules: [{ required: true, message: '请输入培训机构', trigger: 'blur' }]
},
{
type: 'v-input',
label: '课程名称',
model: 'course_cn',
rules: [{ required: true, message: '请输入课程名称', trigger: 'blur' }]
}
]
}
}
/**
* 推荐信
*/
export default {
id: 'application_tjx',
title: '推荐信',
required: true,
get: {
action: '/v1.0/application-materials/1005',
callback(data) {
const { reco_letters = [] } = data.data.material
return reco_letters
}
},
update: {
action: '/v1.0/application-materials/1005/put',
beforeRequest(data) {
const reco_letters = data.map(item => {
return ['provider_name', 'provider_phone_number', 'provider_email', 'provider_relationship'].reduce(
(result, key) => {
result[key] = item[key]
return result
},
{}
)
})
return { reco_letters }
}
},
form: {
hasAdd: true,
options: {
labelWidth: '140px'
},
items: [
{
type: 'v-input',
label: '推荐人姓名',
model: 'provider_name',
attrs: { placeholder: '请输入推荐人姓名' },
rules: [{ required: true, message: '请输入推荐人姓名', trigger: 'blur' }]
},
{
type: 'v-input',
label: '推荐人电话',
model: 'provider_phone_number',
attrs: { placeholder: '请输入推荐人电话' },
rules: [{ required: true, message: '请输入推荐人电话', trigger: 'blur' }]
},
{
type: 'v-input',
label: '推荐人邮箱',
model: 'provider_email',
attrs: { placeholder: '请输入推荐人邮箱' },
rules: [{ required: true, message: '请输入推荐人邮箱', trigger: 'blur' }]
},
{
type: 'v-select',
values: [
{ value: '老师/导师' },
{ value: '领导' },
{ value: '同学' },
{ value: '同事' },
{ value: '亲属' },
{ value: '朋友' },
{ value: '其他' }
],
label: '与推荐人关系',
model: 'provider_relationship',
rules: [{ required: true, message: '请选择与推荐人关系', trigger: 'change' }]
}
]
}
}
export default {
id: 'application_wfzzm',
title: '无犯罪证明',
get: {
action: '/v1.0/application-materials/1005',
callback(data) {
const { attachments = [] } = data.data.material
const NO_CRIMINAL_CERT = attachments.filter(item => {
return item.file_type_id === 'NO_CRIMINAL_CERT'
})
return { NO_CRIMINAL_CERT }
}
},
form: {
hasButton: false,
options: {},
items: [
{
type: 'v-upload',
required: true,
model: 'NO_CRIMINAL_CERT',
attrs: {
action: '/v1.0/application-materials/attachments/1005/put',
deleteAction: '/v1.0/application-materials/attachments/1005/delete',
data: { file_type: 'NO_CRIMINAL_CERT' }
},
prepend: `
<p>第一步:点击下载按键获取无犯罪证明模板</p>
<p><a href="https://www.baidu.com" target="_blank" download>下载模板</a></p>
<p>第二步:打印文件后填写内容并签字上传至电脑,点击下方按钮上传文件</p>
`
}
]
}
}
export default {
id: 'interview_byz',
title: '学位证书',
get: {
action: '/v1.0/application-materials/1005',
callback(data) {
const { attachments = [] } = data.data.material
const DEGREE_CERT_CN = attachments.filter(item => {
return item.file_type_id === 'DEGREE_CERT_CN'
})
return { DEGREE_CERT_CN }
}
},
form: {
hasButton: false,
options: {},
items: [
{
type: 'v-upload',
required: true,
model: 'DEGREE_CERT_CN',
attrs: {
action: '/v1.0/application-materials/attachments/1005/put',
deleteAction: '/v1.0/application-materials/attachments/1005/delete',
data: { file_type: 'DEGREE_CERT_CN' }
},
append: '注意事项:需要将证书原件扫描或拍照后提交,请确保证书内容清晰可辨。'
}
]
}
}
export default {
id: 'interview_cjd',
title: '成绩单(中+英)',
get: {
action: '/v1.0/application-materials/1005',
callback(data) {
const { attachments = [] } = data.data.material
return attachments.reduce(
(result, item) => {
if (item.file_type_id === 'REPORT_CARD_CN') {
result.REPORT_CARD_CN.push(item)
}
if (item.file_type_id === 'REPORT_CARD_EN') {
result.REPORT_CARD_EN.push(item)
}
return result
},
{ REPORT_CARD_CN: [], REPORT_CARD_EN: [] }
)
}
},
form: {
hasButton: false,
options: { 'label-position': 'top' },
hint: `
<p>成绩单:中英文成绩单各上传一个文件</p>
<p>注意事项:需要将证书原件扫描或拍照后提交,请确保证书内容清晰可辨。</p>
`,
items: [
{
type: 'v-upload',
label: '中文成绩单',
required: true,
model: 'REPORT_CARD_CN',
attrs: {
action: '/v1.0/application-materials/attachments/1005/put',
deleteAction: '/v1.0/application-materials/attachments/1005/delete',
data: { file_type: 'REPORT_CARD_CN' }
}
},
{
type: 'v-upload',
label: '英文成绩单',
required: true,
model: 'REPORT_CARD_EN',
attrs: {
action: '/v1.0/application-materials/attachments/1005/put',
deleteAction: '/v1.0/application-materials/attachments/1005/delete',
data: { file_type: 'REPORT_CARD_EN' }
}
}
]
}
}
import byz from './byz'
import cjd from './cjd'
import zp from './zp'
export default {
id: 'interview',
title: '申请面试',
children: [byz, cjd, zp]
}
export default {
id: 'interview_zp',
title: '2寸照片',
get: {
action: '/v1.0/application-materials/1005',
callback(data) {
const { attachments = [] } = data.data.material
const PERSONAL_PHOTO_FOR_ID = attachments.filter(item => {
return item.file_type_id === 'PERSONAL_PHOTO_FOR_ID'
})
return { PERSONAL_PHOTO_FOR_ID }
}
},
form: {
hasButton: false,
options: {},
items: [
{
type: 'v-upload',
required: true,
model: 'PERSONAL_PHOTO_FOR_ID',
attrs: {
action: '/v1.0/application-materials/attachments/1005/put',
deleteAction: '/v1.0/application-materials/attachments/1005/delete',
data: { file_type: 'PERSONAL_PHOTO_FOR_ID' }
},
prepend: '2寸照片:以电子版的形式上传文件',
append: '注意事项:需要将证书原件扫描或拍照后提交,请确保证书内容清晰可辨。'
}
]
}
}
import Vue from 'vue' import Vue from 'vue'
import App from './App.vue' import App from './ciis/App.vue'
import VueForm from '../src/index' import VueForm from '../src/index'
Vue.use(VueForm) Vue.use(VueForm)
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
"axios": "^0.20.0", "axios": "^0.20.0",
"core-js": "^3.6.5", "core-js": "^3.6.5",
"element-ui": "^2.13.2", "element-ui": "^2.13.2",
"qs": "^6.9.4",
"vue": "^2.6.11" "vue": "^2.6.11"
}, },
"devDependencies": { "devDependencies": {
......
<template> <template>
<div class="ezj-container"> <div class="v-layout">
<ezj-aside :width="asideWidth"> <div class="v-layout-aside">
<ezj-menu :default-active="defaultActive" :menus="menus" @select="onSelect"></ezj-menu> <v-menu :default-active="defaultActive" :datalist="menus" @select="onSelect"></v-menu>
</ezj-aside> </div>
<ezj-main :title="currentPage.title" v-if="currentPage" :key="activeId"> <div class="v-layout-main" v-if="page" :key="activeId">
<slot> <slot>
<template v-if="currentPage.form"> <template v-if="page.tabs">
<ezj-form-pane v-bind="currentPage" v-on="$listeners"></ezj-form-pane> <v-card-tabs v-bind="page" v-on="$listeners"></v-card-tabs>
</template>
<template v-else>
<v-card v-bind="page" v-on="$listeners">
<div class="v-layout-html" v-html="page.html" v-if="page.html"></div>
<v-form-pane v-bind="page" v-on="$listeners" v-if="page.form"></v-form-pane>
</v-card>
</template> </template>
</slot> </slot>
</ezj-main> </div>
</div> </div>
</template> </template>
<script> <script>
import EzjAside from '@/components/layout/Aside' import VMenu from '@/packages/layout/src/menu'
import EzjMenu from '@/components/layout/Menu' import VCard from '@/packages/layout/src/card'
import EzjMain from '@/components/layout/Main' import VCardTabs from '@/packages/layout/src/card-tabs'
import EzjFormPane from '@/components/layout/FormPane' import VFormPane from '@/packages/form/src/form-pane'
export default { export default {
name: 'VueForm', name: 'VueForm',
...@@ -32,14 +38,14 @@ export default { ...@@ -32,14 +38,14 @@ export default {
}, },
defaultActive: { type: String } defaultActive: { type: String }
}, },
components: { EzjAside, EzjMenu, EzjMain, EzjFormPane }, components: { VMenu, VCard, VCardTabs, VFormPane },
data() { data() {
return { return {
activeId: this.defaultActive activeId: this.defaultActive
} }
}, },
computed: { computed: {
currentPage() { page() {
return this.getDeepItem(this.menus, this.activeId) return this.getDeepItem(this.menus, this.activeId)
} }
}, },
...@@ -66,7 +72,24 @@ export default { ...@@ -66,7 +72,24 @@ export default {
</script> </script>
<style lang="scss"> <style lang="scss">
.ezj-container { :root {
--main-color: #af1b40;
}
.v-layout {
display: flex; display: flex;
} }
.v-layout-aside {
width: 190px;
background: #fff;
border-radius: 5px;
}
.v-layout-main {
flex: 1;
margin-left: 20px;
}
.v-layout-html {
font-size: 14px;
color: #222;
line-height: 34px;
}
</style> </style>
...@@ -47,7 +47,7 @@ const components = [ ...@@ -47,7 +47,7 @@ const components = [
UploadForm UploadForm
] ]
const install = function(Vue, opts = {}) { const install = function(Vue) {
// locale.use(opts.locale); // locale.use(opts.locale);
// locale.i18n(opts.i18n); // locale.i18n(opts.i18n);
......
...@@ -9,7 +9,8 @@ ...@@ -9,7 +9,8 @@
:rules="item.rules || []" :rules="item.rules || []"
:size="item.size" :size="item.size"
> >
<el-input :style="{ width: item.modelWidth || item['model-width'] || '89%' }" <el-input
:style="{ width: item.modelWidth || item['model-width'] || '89%' }"
v-bind="item.attrs || {}" v-bind="item.attrs || {}"
v-on="$listeners" v-on="$listeners"
v-model.trim="formData[item.model]" v-model.trim="formData[item.model]"
...@@ -17,10 +18,12 @@ ...@@ -17,10 +18,12 @@
:placeholder="item.placeholder || ''" :placeholder="item.placeholder || ''"
> >
</el-input> </el-input>
<template v-if="formData[item.model] !== null && formData[item.model] !== '' && formData[item.model] !== undefined"> <template
<div class="self-icon el-icon-circle-check" style="color: #237f00;"></div> v-if="formData[item.model] !== null && formData[item.model] !== '' && formData[item.model] !== undefined"
>
<div class="self-icon el-icon-circle-check" style="color: #237f00"></div>
</template> </template>
<div class="self-icon el-icon-circle-close" style="color: #b01c40;"></div> <div class="self-icon el-icon-circle-close" style="color: #b01c40"></div>
</el-form-item> </el-form-item>
</div> </div>
</template> </template>
...@@ -32,31 +35,35 @@ export default { ...@@ -32,31 +35,35 @@ export default {
props: { props: {
item: { item: {
type: Object, type: Object,
default () { default() {
return {} return {}
} }
}, },
formData: { formData: {
type: Object, type: Object,
default () { default() {
return {} return {}
} }
} }
}, },
data () { data() {
return {} return {}
} }
} }
</script> </script>
<style lang="scss"> <style lang="scss">
.self-icon { .self-icon {
display: none !important; display: none !important;
vertical-align: middle; vertical-align: middle;
margin-left: 10px; margin-left: 10px;
font-size: 21px; font-size: 21px;
line-height: 22px; line-height: 22px;
} }
.is-error .self-icon.el-icon-circle-close { display: inline-block !important; } .is-error .self-icon.el-icon-circle-close {
.is-success .self-icon.el-icon-circle-check { display: inline-block !important; } display: inline-block !important;
}
.is-success .self-icon.el-icon-circle-check {
display: inline-block !important;
}
</style> </style>
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
:rules="item.rules || []" :rules="item.rules || []"
:size="item.size" :size="item.size"
> >
<div v-html="item.prepend"></div>
<el-upload <el-upload
:action="item.action" :action="item.action"
:data="item.data" :data="item.data"
...@@ -18,14 +19,17 @@ ...@@ -18,14 +19,17 @@
:show-file-list="false" :show-file-list="false"
:file-list="formData[item.model]" :file-list="formData[item.model]"
:disabled="item.disabled || false" :disabled="item.disabled || false"
v-bind="item.attrs || {}"> v-bind="item.attrs || {}"
>
<el-button type="primary" size="mini">点击上传</el-button> <el-button type="primary" size="mini">点击上传</el-button>
<template v-if="formData[item.model] !== null && formData[item.model] !== '' && formData[item.model] !== undefined"> <template
<div class="self-icon el-icon-circle-check" style="color: #237f00;"></div> v-if="formData[item.model] !== null && formData[item.model] !== '' && formData[item.model] !== undefined"
>
<div class="self-icon el-icon-circle-check" style="color: #237f00"></div>
</template> </template>
<div class="self-icon el-icon-circle-close" style="color: #b01c40;"></div> <div class="self-icon el-icon-circle-close" style="color: #b01c40"></div>
</el-upload> </el-upload>
<div style="overflow: hidden; padding: 20px 0 0 0;"> <div style="overflow: hidden; padding: 20px 0 0 0">
<template v-if="filesArr.length"> <template v-if="filesArr.length">
<!-- 遍历显示文件 --> <!-- 遍历显示文件 -->
<template v-for="(item, index) in filesArr"> <template v-for="(item, index) in filesArr">
...@@ -56,7 +60,8 @@ ...@@ -56,7 +60,8 @@
</template> </template>
</template> </template>
</div> </div>
<div class='info' style="line-height: 1.5;" v-html="item.html"></div> <div class="info" style="line-height: 1.5" v-html="item.html"></div>
<div v-html="item.append"></div>
</el-form-item> </el-form-item>
</div> </div>
</template> </template>
...@@ -70,37 +75,37 @@ export default { ...@@ -70,37 +75,37 @@ export default {
props: { props: {
item: { item: {
type: Object, type: Object,
default () { default() {
return {} return {}
} }
}, },
formData: { formData: {
type: Object, type: Object,
default () { default() {
return {} return {}
} }
} }
}, },
data () { data() {
return { return {
project_id: '', project_id: '',
filesArr: [] filesArr: []
} }
}, },
methods: { methods: {
beforeUploadFile (file) {}, beforeUploadFile() {},
onSuccessFile (response, file, fileList) { onSuccessFile(response, file) {
response.url = response.file || '' response.url = response.file || ''
response.sso_file_name = file.name response.sso_file_name = file.name
this.filesArr.push(response) this.filesArr.push(response)
// this.$emit('onSubmit') // this.$emit('onSubmit')
}, },
deleteFiles (index) { deleteFiles(index) {
const temp = this.filesArr[index] const temp = this.filesArr[index]
deleteFile({ deleteFile({
action: this.item.deleteAction + '/' + temp.id + '?project_id=' + this.item.data.project_id, action: this.item.deleteAction + '/' + temp.id + '?project_id=' + this.item.data.project_id,
onError: () => {}, onError: () => {},
onSuccess: (res) => { onSuccess: res => {
if (res.status === 200) { if (res.status === 200) {
this.filesArr.splice(index, 1) this.filesArr.splice(index, 1)
} }
...@@ -112,7 +117,7 @@ export default { ...@@ -112,7 +117,7 @@ export default {
formData: { formData: {
immediate: true, immediate: true,
deep: true, deep: true,
handler (value) { handler(value) {
/* 单独处理 - ajax结果在组件渲染之后 */ /* 单独处理 - ajax结果在组件渲染之后 */
if (value[this.item.model] && value[this.item.model].length && !this.filesArr.length) { if (value[this.item.model] && value[this.item.model].length && !this.filesArr.length) {
this.filesArr = value[this.item.model] this.filesArr = value[this.item.model]
...@@ -125,17 +130,21 @@ export default { ...@@ -125,17 +130,21 @@ export default {
</script> </script>
<style lang="scss"> <style lang="scss">
.self-icon { .self-icon {
display: none !important; display: none !important;
vertical-align: middle; vertical-align: middle;
margin-left: 10px; margin-left: 10px;
font-size: 21px; font-size: 21px;
line-height: 22px; line-height: 22px;
} }
.is-error .self-icon.el-icon-circle-close { display: inline-block !important; } .is-error .self-icon.el-icon-circle-close {
.is-success .self-icon.el-icon-circle-check { display: inline-block !important; } display: inline-block !important;
}
.is-success .self-icon.el-icon-circle-check {
display: inline-block !important;
}
.show-file { .show-file {
position: relative; position: relative;
float: left; float: left;
margin-right: 10px; margin-right: 10px;
...@@ -194,5 +203,5 @@ export default { ...@@ -194,5 +203,5 @@ export default {
display: block; display: block;
} }
} }
} }
</style> </style>
## 组件简介
| 字段值 | 说明 | 字段属性 | 默认值 |
| ------- | ------------------------- | ------- | `form-form` |
| `type` | 类型:`String`; 说明:组件类型名 | 自定义字段 | `''` |
| `label` | 类型:`String`; 说明:组件左侧显示名称 | element-ui对应字段 | `''` |
| `placeholder` | 类型:`String`; 说明:组件input框中,默认提示文字 | element-ui对应字段 | `''` |
| `rules` | 类型:`Array`; 说明:组件错误提示规则 | element-ui对应字段 | `''` |
| `model` | 类型:`String`; 说明:数据上传和回显对照字段 | 自定义字段 | `''` |
| `defaultValue` | 类型:`String`; 说明:当前默认显示值 | 自定义字段 | `''` |
* 其他属性 [参考文档]([https://](https://element.eleme.cn/#/zh-CN/component/input))
import Form from './src/formForm'
/* istanbul ignore next */
Form.install = function (Vue) {
Vue.component(Form.name, Form)
}
export default Form
<template>
<div class="ezj-aside" :style="style">
<slot></slot>
</div>
</template>
<script>
export default {
name: 'EzjAside',
props: {
width: { String, default: '295px' }
},
computed: {
style() {
return {
width: this.width
}
}
}
}
</script>
<style lang="scss">
.ezj-aside {
width: 295px;
}
</style>
<template>
<div class="ezj-main">
<div class="ezj-main__hd">
<slot name="header">
<h1 class="ezj-main__title">{{title}}</h1>
</slot>
</div>
<div class="ezj-main__bd">
<slot></slot>
</div>
</div>
</template>
<script>
export default {
props: {
title: String
}
}
</script>
<style lang="scss">
.ezj-main {
flex: 1;
margin: 0 40px;
}
.ezj-main__hd {
margin-bottom: 26px;
}
.ezj-main__title {
font-size: 24px;
line-height: 1.4;
color: #000;
}
</style>
<template>
<div class="ezj-submenu">
<template v-for="submenu in menus">
<div
class="ezj-submenu__item"
:class="{'is-active': submenu.isActive}"
:key="submenu.id"
@click="$emit('onClick', submenu.id, submenu)"
>
<span>{{submenu.title}}</span>
<!-- 是否必选 -->
<template v-if="submenu.showRequired">{{submenu.required ? '': '(可选)'}}</template>
<!-- 进度 -->
<template v-if="submenu.showProgress">
<span
:class="submenu.progress ? 'is-success' : 'is-error'"
>{{submenu.progress ? '(已完成)': '(未完成)'}}</span>
</template>
</div>
</template>
</div>
</template>
<script>
export default {
name: 'Submenu',
props: { menus: Array },
data() {
return {}
}
}
</script>
<style lang="scss">
.ezj-submenu__item.is-active {
color: #c41230;
}
.is-success {
color: #12c44a;
}
.is-error {
color: #c41230;
}
</style>
import ElemForm from './components/elem-form' import {
import FormForm from './components/form-form' Dialog,
Input,
Radio,
RadioGroup,
Checkbox,
CheckboxGroup,
Switch,
Select,
Option,
OptionGroup,
Button,
ButtonGroup,
DatePicker,
TimeSelect,
TimePicker,
Form,
FormItem,
Tabs,
TabPane,
Icon,
Upload,
Message
} from 'element-ui'
import VueForm from './VueForm' import VueForm from './VueForm'
import VInput from './packages/input'
import VSelect from './packages/select'
import VRadio from './packages/radio'
import VCheckbox from './packages/checkbox'
import VDatepicker from './packages/datepicker'
import VUpload from './packages/upload'
const components = [VueForm] const components = [VueForm, VInput, VSelect, VRadio, VCheckbox, VDatepicker, VUpload]
const install = function(Vue) { const install = function(Vue) {
if (install.installed) return if (install.installed) return
Vue.use(Dialog)
Vue.use(ElemForm) Vue.use(Input)
Vue.use(FormForm) Vue.use(Radio)
Vue.use(RadioGroup)
Vue.use(Checkbox)
Vue.use(CheckboxGroup)
Vue.use(Switch)
Vue.use(Select)
Vue.use(Option)
Vue.use(OptionGroup)
Vue.use(Button)
Vue.use(ButtonGroup)
Vue.use(DatePicker)
Vue.use(TimeSelect)
Vue.use(TimePicker)
Vue.use(Form)
Vue.use(FormItem)
Vue.use(Tabs)
Vue.use(TabPane)
Vue.use(Icon)
Vue.use(Upload)
Vue.prototype.$message = Message
// 遍历注册全局组件 // 遍历注册全局组件
components.map(component => Vue.component(component.name, component)) components.map(component => Vue.component(component.name, component))
} }
......
import VCheckbox from './src/main.vue'
VCheckbox.install = function(Vue) {
Vue.component(VCheckbox.name, VCheckbox)
}
export default VCheckbox
<template>
<el-checkbox-group v-model="data[options.model]" v-bind="$attrs">
<el-checkbox v-for="item in options.values" :label="item.label" :value="item.value" :key="item.value"></el-checkbox>
</el-checkbox-group>
</template>
<script>
export default {
name: 'VCheckbox',
props: {
options: {
type: Object,
default() {
return {}
}
},
data: {
type: Object,
default() {
return {}
}
}
}
}
</script>
\ No newline at end of file
import VDatepicker from './src/main.vue'
VDatepicker.install = function(Vue) {
Vue.component(VDatepicker.name, VDatepicker)
}
export default VDatepicker
<template>
<el-date-picker v-model="data[options.model]" v-bind="$attrs" style="width: 300px" />
</template>
<script>
export default {
name: 'VDatepicker',
props: {
options: {
type: Object,
default() {
return {}
}
},
data: {
type: Object,
default() {
return {}
}
}
}
}
</script>
\ No newline at end of file
import VFormPane from '../form/src/form-pane.vue'
VFormPane.install = function(Vue) {
Vue.component(VFormPane.name, VFormPane)
}
export default VFormPane
import VForm from './form.vue'
VForm.install = function(Vue) {
Vue.component(VForm.name, VForm)
}
export default VForm
<template> <template>
<div class="ezj-form-pane"> <div class="v-form-pane">
<template v-if="form.hint"> <template v-if="form.hint">
<div class="ezj-form-pane__hint" v-html="form.hint"></div> <div class="v-form-pane__hint" v-html="form.hint"></div>
</template> </template>
<!-- 多个表单 --> <!-- 多个表单 -->
<template v-if="form.hasAdd"> <template v-if="form.hasAdd && isMultiple">
<template v-if="isMultiple">
<template v-for="(item, index) in model"> <template v-for="(item, index) in model">
<div class="ejz-form-pane_group" :key="index"> <div class="v-form-group" :key="index">
<div class="remove" @click="handleRemove(index)"> <v-form
<i class="el-icon-close"></i>
</div>
<form-form
:options="form.options" :options="form.options"
:model="item"
:items="form.items" :items="form.items"
:model="item"
:hasButton="false" :hasButton="false"
:submitText="form.submitText"
v-on="$listeners"
ref="form" ref="form"
></form-form> ></v-form>
<div class="v-form-group__remove" @click="handleRemove(index)">删除</div>
</div> </div>
</template> </template>
<el-button @click="handleAdd">增加一项</el-button> <div class="v-form-group__add">
<el-button type="primary" @click="handleSubmit">保存</el-button> <i class="el-icon-circle-plus" @click="handleAdd"></i>
</template> </div>
<el-button type="primary" @click="handleSubmit">{{ form.submitText || '提交' }}</el-button>
</template> </template>
<!-- 一个表单 --> <!-- 一个表单 -->
<template v-else> <template v-else>
<form-form <v-form
:options="form.options" :options="form.options"
:model="model"
:items="form.items" :items="form.items"
@onSubmit="onSubmit" :model="model"
:hasButton="form.hasButton" :hasButton="form.hasButton"
:submitText="form.submitText"
@onSubmit="onSubmit"
v-on="$listeners"
ref="form" ref="form"
></form-form> ></v-form>
</template> </template>
</div> </div>
</template> </template>
<script> <script>
import axios from 'axios' import httpRequest from '@/utils/axios'
import VForm from './form.vue'
export default { export default {
name: 'EzjFormPane', name: 'VFormPane',
components: {}, components: { VForm },
props: { props: {
title: String, title: String,
get: Object, get: Object,
...@@ -77,7 +80,7 @@ export default { ...@@ -77,7 +80,7 @@ export default {
if (beforeRequest) { if (beforeRequest) {
data = beforeRequest(data) data = beforeRequest(data)
} }
axios({ httpRequest({
method, method,
url, url,
params, params,
...@@ -85,23 +88,16 @@ export default { ...@@ -85,23 +88,16 @@ export default {
headers headers
}) })
.then(res => { .then(res => {
let { data } = res
// 默认数据设置 // 默认数据设置
if (this.form.hasAdd && Array.isArray(data) && !data.length) { if (this.form.hasAdd && Array.isArray(res) && !res.length) {
data.push(Object.assign({}, this.form.defaultModel)) res.push(Object.assign({}, this.form.defaultModel))
} }
if (callback) { if (callback) {
data = callback(data) res = callback(res)
}
this.model = data
})
.catch(error => {
if (error.response) {
this.$emit('error', error.response.data)
} else {
throw error
} }
this.model = res
}) })
.catch(error => this.$emit('error', error))
}, },
// 更新 // 更新
updateData(formData) { updateData(formData) {
...@@ -111,31 +107,13 @@ export default { ...@@ -111,31 +107,13 @@ export default {
} }
// 自定义数据和表单数据合并 // 自定义数据和表单数据合并
formData = Object.assign({}, formData, data) formData = Object.assign({}, formData, data)
// 自定义header和默认header合并 httpRequest
headers = Object.assign({ 'Content-Type': 'application/x-www-form-urlencoded' }, headers)
// 表单数据序列化
if (headers['Content-Type'] === 'application/x-www-form-urlencoded') {
const params = new URLSearchParams()
for (const key in formData) {
const value = formData[key]
params.append(key, typeof value === 'object' ? JSON.stringify(value) : value)
}
formData = params
}
axios
.post(action, formData, { headers }) .post(action, formData, { headers })
.then(res => { .then(res => {
const { data } = res callback && callback(res)
callback && callback(data) this.$emit('success', res)
this.$emit('success', data)
})
.catch(error => {
if (error.response) {
this.$emit('error', error.response.data)
} else {
throw error
}
}) })
.catch(error => this.$emit('error', error))
}, },
onSubmit(data) { onSubmit(data) {
this.updateData(data) this.updateData(data)
...@@ -164,31 +142,29 @@ export default { ...@@ -164,31 +142,29 @@ export default {
</script> </script>
<style lang="scss"> <style lang="scss">
.ezj-form-pane__hint { .v-form-pane__hint {
margin-bottom: 20px; margin-bottom: 20px;
} }
.ejz-form-pane_group { .v-form-group {
position: relative; position: relative;
margin-bottom: 20px; margin-bottom: 20px;
padding: 15px; border-bottom: 1px solid #f1f1f1;
border: 2px solid #c41230; }
border-radius: 10px; .v-form-group__remove {
.remove {
position: absolute; position: absolute;
top: -12px; bottom: 20px;
right: -12px; right: 0;
z-index: 999; font-size: 14px;
font-size: 20px; color: var(--main-color);
line-height: 24px; cursor: pointer;
}
.v-form-group__add {
margin-bottom: 20px;
padding-bottom: 20px;
font-size: 30px;
color: var(--main-color);
text-align: center; text-align: center;
color: #fff;
cursor: pointer; cursor: pointer;
background-color: #c41230; border-bottom: 1px solid #f1f1f1;
width: 24px;
height: 24px;
border-radius: 50%;
overflow: hidden;
}
} }
</style> </style>
<template> <template>
<div class="form-form"> <div class="v-form">
<div class="v-form__prepend" v-html="options.prepend"></div>
<el-form v-bind="options" ref="form" :model="ruleForm" @submit.native.prevent v-on="$listeners"> <el-form v-bind="options" ref="form" :model="ruleForm" @submit.native.prevent v-on="$listeners">
<template v-for="item in items"> <template v-for="item in currentItems">
<component :is="item.type" v-bind:key="item.model" :item="item" :formData="ruleForm"></component> <el-form-item v-bind="item" :prop="item.model" :key="item.model">
<div class="v-form-item__prepend" v-html="item.prepend"></div>
<component :is="item.type" :options="item" :data="ruleForm" v-on="$listeners" v-bind="item.attrs"></component>
<div class="v-form-item__append" v-html="item.append"></div>
</el-form-item>
</template> </template>
<el-form-item v-if="hasButton"> <el-form-item v-if="hasButton">
<slot> <slot name="button">
<el-button type="primary" @click="onSubmit">保存</el-button> <el-button type="primary" @click="onSubmit">{{ submitText }}</el-button>
</slot> </slot>
</el-form-item> </el-form-item>
</el-form> </el-form>
<div class="v-form__append" v-html="options.append"></div>
</div> </div>
</template> </template>
<script> <script>
export default { export default {
name: 'FormForm', name: 'VForm',
componentName: 'FormForm',
props: { props: {
options: { options: {
type: Object, type: Object,
...@@ -30,16 +35,9 @@ export default { ...@@ -30,16 +35,9 @@ export default {
return {} return {}
} }
}, },
items: { items: { type: Array, default: () => [] },
type: Array, hasButton: { type: Boolean, default: true },
default() { submitText: { type: String, default: '提交' }
return []
}
},
hasButton: {
type: Boolean,
default: true
}
}, },
data() { data() {
return { return {
...@@ -58,6 +56,14 @@ export default { ...@@ -58,6 +56,14 @@ export default {
computed: { computed: {
$form() { $form() {
return this.$refs.form return this.$refs.form
},
currentItems() {
return this.items.filter(item => {
if (Object.prototype.hasOwnProperty.call(item, 'isShow')) {
return item.isShow(this.ruleForm)
}
return true
})
} }
}, },
methods: { methods: {
......
import VInput from './src/main.vue'
VInput.install = function(Vue) {
Vue.component(VInput.name, VInput)
}
export default VInput
<template>
<el-input v-model="data[options.model]" v-bind="$attrs" clearable style="width: 300px" />
</template>
<script>
export default {
name: 'VInput',
props: {
options: {
type: Object,
default() {
return {}
}
},
data: {
type: Object,
default() {
return {}
}
}
}
}
</script>
\ No newline at end of file
<template>
<div class="v-form-card">
<div class="v-form-card__hd">
<slot name="header">
<h1 class="v-form-card__title">{{ title }}</h1>
<div class="v-form-card__back" @click="$emit('back')">
<i class="el-icon-arrow-left"></i>
<span>{{ backText }}</span>
</div>
</slot>
</div>
<div class="v-form-card__bd">
<v-form-pane v-bind="$attrs" v-on="$listeners"></v-form-pane>
</div>
</div>
</template>
<script>
import VFormPane from '../../form/src/form-pane'
export default {
name: 'VCardForm',
props: {
title: { type: String },
backText: { type: String, default: '返回报名系统' }
},
components: { VFormPane }
}
</script>
<style lang="scss">
.v-form-card {
padding: 20px;
background: #fff;
border-radius: 5px;
}
.v-form-card__hd {
padding-bottom: 10px;
display: flex;
align-items: center;
justify-content: space-between;
border-bottom: 1px solid #f5f6fa;
}
.v-form-card__title {
font-size: 14px;
font-weight: bold;
line-height: 1;
color: #222;
}
.v-form-card__back {
font-size: 14px;
line-height: 1;
color: #57acff;
cursor: pointer;
}
.v-form-card__bd {
margin-top: 20px;
}
</style>
\ No newline at end of file
<template>
<div class="v-tabs-card">
<div class="v-tabs-card__back" @click="$emit('back')">
<i class="el-icon-arrow-left"></i>
<span>{{ backText }}</span>
</div>
<el-tabs type="card" v-model="activeName">
<el-tab-pane :lazy="true" :label="tab.title" :name="tab.id" :key="tab.id" v-for="tab in tabs">
<template v-slot:label>
{{ tab.title }}
<span class="red" v-if="tab.required">*</span>
</template>
<v-form-pane v-bind="tab" v-on="$listeners"></v-form-pane>
</el-tab-pane>
</el-tabs>
</div>
</template>
<script>
import VFormPane from '../../form/src/form-pane'
export default {
name: 'VCardTabs',
props: {
tabs: { type: Array, default: () => [] },
backText: { type: String, default: '返回报名系统' }
},
components: { VFormPane },
data() {
return {
activeName: ''
}
},
watch: {
tabs: {
immediate: true,
handler(list) {
const [first] = list
this.activeName = first.id
}
}
}
}
</script>
<style lang="scss">
.v-tabs-card {
position: relative;
min-height: 100%;
background: #fff;
border-radius: 5px;
padding-right: 20px;
.el-tabs__item {
color: #717171;
background-color: #f5f6fa;
&.is-active {
color: #222;
background-color: #fff;
}
}
.el-tabs__content {
padding: 20px 0 20px 20px;
overflow: inherit;
}
}
.v-tabs-card__back {
position: absolute;
font-size: 14px;
line-height: 40px;
color: #57acff;
right: 20px;
z-index: 1;
cursor: pointer;
}
.red {
color: var(--main-color);
}
</style>
\ No newline at end of file
<template>
<div class="v-card">
<div class="v-card__hd">
<slot name="header">
<h1 class="v-card__title">{{ title }}</h1>
<div class="v-card__back" @click="$emit('back')">
<i class="el-icon-arrow-left"></i>
<span>{{ backText }}</span>
</div>
</slot>
</div>
<div class="v-card__bd">
<slot></slot>
</div>
</div>
</template>
<script>
export default {
name:'VCard',
props: {
title: { type: String },
backText: { type: String, default: '返回报名系统' }
}
}
</script>
<style lang="scss">
.v-card {
padding: 20px;
min-height: 100%;
background: #fff;
border-radius: 5px;
box-sizing: border-box;
}
.v-card__hd {
padding-bottom: 10px;
display: flex;
align-items: center;
justify-content: space-between;
border-bottom: 1px solid #f5f6fa;
}
.v-card__title {
font-size: 14px;
font-weight: bold;
line-height: 1;
color: #222;
}
.v-card__back {
font-size: 14px;
line-height: 1;
color: #57acff;
cursor: pointer;
}
.v-card__bd {
margin-top: 20px;
}
</style>
\ No newline at end of file
<template> <template>
<div class="ezj-menu"> <div class="v-menu">
<template v-for="menu in menus"> <template v-for="item in datalist">
<div <div :class="{ 'v-menu__item': true, 'is-active': item.isActive }" :key="item.id">
:class="{'ezj-menu__item': true,'has-shadow': menu.hasShadow, 'is-active': menu.isActive}" <div class="v-menu__title" @click="handleSelect(item.id, item)">
:key="menu.id" <span>{{ item.title }}</span>
>
<div class="ezj-menu__title" @click="handleSelect(menu.id, menu)">{{menu.title}}</div>
<template v-if="menu.children">
<template v-if="menu.isGroup">
<template v-for="submenu in menu.children">
<div class="ezj-menu-group" :key="submenu.title" v-show="menu.isActive">
<div class="ezj-menu-group__title">{{submenu.title}}</div>
<ezj-submenu :menus="submenu.children" @onClick="handleSelect"></ezj-submenu>
</div> </div>
</template> <template v-if="item.children">
</template>
<template v-else>
<!-- 子菜单 --> <!-- 子菜单 -->
<ezj-submenu :menus="menu.children" @onClick="handleSelect" v-show="menu.isActive"></ezj-submenu> <v-submenu :datalist="item.children" @select="handleSelect"></v-submenu>
</template>
</template> </template>
</div> </div>
</template> </template>
...@@ -26,24 +15,17 @@ ...@@ -26,24 +15,17 @@
</template> </template>
<script> <script>
import EzjSubmenu from './Submenu' import VSubmenu from './submenu'
export default { export default {
name: 'EzjMenu', name: 'VMenu',
components: { EzjSubmenu }, components: { VSubmenu },
props: { props: {
asidewidth: String, datalist: { type: Array, default: () => [] },
menus: {
type: Array,
default() {
return []
}
},
router: { type: Boolean, default: false }, router: { type: Boolean, default: false },
defaultActive: { type: String } defaultActive: { type: String }
}, },
data() { data() {
return { return {
menuList: [],
currentActive: null, currentActive: null,
activeIds: [] activeIds: []
} }
...@@ -54,9 +36,9 @@ export default { ...@@ -54,9 +36,9 @@ export default {
handler(value) { handler(value) {
this.currentActive = value this.currentActive = value
// 设置选中的ID,包含父级的ID // 设置选中的ID,包含父级的ID
this.activeIds = this.setActiveIds(this.menus, value) this.activeIds = this.setActiveIds(this.datalist, value)
// 更新选中状态 // 更新选中状态
this.changeActiveStatus(this.menus, this.activeIds) this.changeActiveStatus(this.datalist, this.activeIds)
} }
} }
}, },
...@@ -67,9 +49,9 @@ export default { ...@@ -67,9 +49,9 @@ export default {
// 当前ID // 当前ID
this.currentActive = id this.currentActive = id
// 设置选中的ID,包含父级的ID // 设置选中的ID,包含父级的ID
this.activeIds = this.setActiveIds(this.menus, id) this.activeIds = this.setActiveIds(this.datalist, id)
// 更新选中状态 // 更新选中状态
this.changeActiveStatus(this.menus, this.activeIds) this.changeActiveStatus(this.datalist, this.activeIds)
this.$emit('select', id) this.$emit('select', id)
}, },
// 更新菜单数据isActve的状态 // 更新菜单数据isActve的状态
...@@ -115,8 +97,8 @@ export default { ...@@ -115,8 +97,8 @@ export default {
}, },
beforeMount() { beforeMount() {
// 没有设置默认选中的, // 没有设置默认选中的,
if (!this.defaultActive && this.menus.length) { if (!this.defaultActive && this.datalist.length) {
const [first] = this.menus const [first] = this.datalist
this.handleSelect(first.id, first) this.handleSelect(first.id, first)
} }
} }
...@@ -124,50 +106,22 @@ export default { ...@@ -124,50 +106,22 @@ export default {
</script> </script>
<style lang="scss"> <style lang="scss">
.ezj-menu__item { .v-menu {
margin-bottom: 10px; margin: 20px 0;
&.has-shadow {
box-shadow: 0px 0px 20px 0px rgba(0, 0, 0, 0.08);
.ezj-submenu__item {
margin: 20px;
}
}
&.is-active {
.ezj-menu__title {
color: #fff;
background-color: #c41230;
border: 0;
}
}
}
.ezj-menu__title {
height: 60px;
font-size: 18px;
line-height: 60px;
color: #000;
text-align: center;
border: 1px solid #d8dce6;
box-sizing: border-box;
cursor: pointer;
&:hover {
color: #fff;
background-color: #c41230;
border: 0;
}
} }
.ezj-menu-group__title { .v-menu__item {
margin: 10px 0; margin-bottom: 10px;
}
.ezj-submenu {
overflow: hidden;
} }
.ezj-submenu__item { .v-menu__title {
margin: 10px 0; padding-left: 60px;
font-size: 18px; height: 44px;
line-height: 20px; font-size: 14px;
cursor: pointer; font-weight: bold;
line-height: 44px;
color: #222;
background: #fff4ee;
border-left-style: solid;
border-left-width: 4px;
border-left-color: var(--main-color);
} }
</style> </style>
<template>
<div class="v-submenu">
<template v-for="item in datalist">
<div
:class="{ 'v-submenu__item': true, 'is-active': item.isActive }"
:key="item.id"
@click="$emit('select', item.id, item)"
>
<span>{{ item.title }}</span>
</div>
</template>
</div>
</template>
<script>
export default {
name: 'VSubmenu',
props: { datalist: { type: Array, default: () => [] } },
data() {
return {}
}
}
</script>
<style lang="scss">
.v-submenu {
padding: 10px 0;
}
.v-submenu__item {
padding-left: 64px;
font-size: 14px;
line-height: 34px;
color: #666;
cursor: pointer;
}
.v-submenu__item.is-active {
color: var(--main-color);
}
</style>
import VRadio from './src/main.vue'
VRadio.install = function(Vue) {
Vue.component(VRadio.name, VRadio)
}
export default VRadio
<template>
<el-radio-group v-model="data[options.model]" v-bind="$attrs">
<el-radio v-for="item in options.values" :label="item.label" :value="item.value" :key="item.value"></el-radio>
</el-radio-group>
</template>
<script>
export default {
name: 'VRadio',
props: {
options: {
type: Object,
default() {
return {}
}
},
data: {
type: Object,
default() {
return {}
}
}
}
}
</script>
\ No newline at end of file
<template>
<div class="v-select-city"></div>
</template>
<script>
export default {
name: 'VSelectCity',
data() {
return {}
},
methods: {}
}
</script>
\ No newline at end of file
import VSelect from './src/main.vue'
VSelect.install = function(Vue) {
Vue.component(VSelect.name, VSelect)
}
export default VSelect
<template>
<el-select v-model="data[options.model]" v-bind="$attrs" style="width: 300px">
<el-option v-for="item in options.values" :label="item.label" :value="item.value" :key="item.value"></el-option>
</el-select>
</template>
<script>
export default {
name: 'VSelect',
props: {
options: {
type: Object,
default() {
return {}
}
},
data: {
type: Object,
default() {
return {}
}
}
}
}
</script>
\ No newline at end of file
import VUpload from './src/main.vue'
VUpload.install = function(Vue) {
Vue.component(VUpload.name, VUpload)
}
export default VUpload
<template>
<div class="v-upload">
<el-upload
v-bind="options.attrs"
action=""
list-type="picture-card"
:multiple="false"
:http-request="handleHttpRequest"
:on-preview="handlePreview"
:on-remove="handleRemove"
:on-success="handleSuccess"
:on-error="handleError"
:on-exceed="handleExceed"
:file-list="fileList"
ref="upload"
>
<i class="el-icon-plus"></i>
</el-upload>
<el-dialog :visible.sync="dialogVisible">
<img width="100%" :src="dialogImageUrl" />
</el-dialog>
</div>
</template>
<script>
import httpRequest from '@/utils/axios'
export default {
name: 'VUpload',
props: {
options: {
type: Object,
default() {
return {}
}
},
data: {
type: Object,
default() {
return {}
}
}
},
data() {
return {
files: [],
dialogVisible: false,
dialogImageUrl: ''
}
},
watch: {
data: {
immediate: true,
deep: true,
handler(data) {
this.files = data[this.options.model] || []
}
}
},
computed: {
fileList() {
return this.files.map(item => {
item.url = item.oss_sign_url
return item
})
}
},
methods: {
// 上传接口请求
handleHttpRequest(xhr) {
let { action, data = {}, headers = {} } = this.options.attrs
data = Object.assign({ file: xhr.file }, data)
headers = Object.assign({ 'Content-Type': 'multipart/form-data' })
httpRequest.post(action, data, { headers }).then(xhr.onSuccess).catch(xhr.onError)
},
// 上传成功
handleSuccess(res) {
this.files = res.data.material.attachments.filter(item => item.file_type_id === this.options.model)
this.data[this.options.model] = this.files
this.$message.success(res.message)
},
// 上传失败
handleError(error) {
this.$message.error(error.message)
},
// 上传数量限制
handleExceed() {
this.$message.warning(`最多上传${this.options.attrs.limit}个文件`)
},
// 预览
handlePreview(file) {
this.dialogVisible = true
this.dialogImageUrl = file.url
},
// 删除
handleRemove(file, fileList) {
let { deleteAction, headers = {} } = this.options.attrs
httpRequest
.post(deleteAction, { item_id: file.id }, { headers })
.then(res => {
this.data[this.options.model] = fileList
this.$message.success(res.message)
})
.catch(error => this.$message.error(error.message))
}
}
}
</script>
<style lang="scss">
.v-upload {
.el-upload--picture-card {
line-height: 116px;
}
.el-upload--picture-card,
.el-upload-list--picture-card .el-upload-list__item {
width: 176px;
height: 116px;
}
.el-upload-list__item {
transition: none;
}
}
</style>
\ No newline at end of file
import axios from 'axios'
const httpRequest = axios.create({
timeout: 60000,
withCredentials: true
})
// 请求拦截
httpRequest.interceptors.request.use(
function(config) {
// 文件上传
if (config.headers['Content-Type'] === 'multipart/form-data') {
let formData = new FormData()
const data = config.data
for (const key in data) {
formData.append(key, data[key])
}
config.data = formData
}
return config
},
function(error) {
return Promise.reject(error)
}
)
// 请求拦截
httpRequest.interceptors.request.use(
function(config) {
return config
},
function(error) {
return Promise.reject(error)
}
)
// 响应拦截
httpRequest.interceptors.response.use(
function(response) {
const { data } = response
if (data.error === '1') {
return Promise.reject(data)
}
return response.data
},
function(error) {
if (error.response) {
return Promise.reject(error.response.data)
} else {
return Promise.reject(error)
}
}
)
export default httpRequest
...@@ -13,6 +13,6 @@ module.exports = { ...@@ -13,6 +13,6 @@ module.exports = {
key: fs.readFileSync(path.join(__dirname, './cert/dev.ezijing.com.key')), key: fs.readFileSync(path.join(__dirname, './cert/dev.ezijing.com.key')),
cert: fs.readFileSync(path.join(__dirname, './cert/dev.ezijing.com.pem')) cert: fs.readFileSync(path.join(__dirname, './cert/dev.ezijing.com.pem'))
}, },
proxy: 'https://api.ezijing.com' proxy: 'http://enrollment-test.c3f0f1f4826b94e23a2c355a9dac8a299.cn-beijing.alicontainer.com'
} }
} }
...@@ -7172,6 +7172,11 @@ qs@6.7.0: ...@@ -7172,6 +7172,11 @@ qs@6.7.0:
resolved "https://registry.npm.taobao.org/qs/download/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" resolved "https://registry.npm.taobao.org/qs/download/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
integrity sha1-QdwaAV49WB8WIXdr4xr7KHapsbw= integrity sha1-QdwaAV49WB8WIXdr4xr7KHapsbw=
qs@^6.9.4:
version "6.9.4"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.4.tgz#9090b290d1f91728d3c22e54843ca44aea5ab687"
integrity sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==
qs@~6.5.2: qs@~6.5.2:
version "6.5.2" version "6.5.2"
resolved "https://registry.npm.taobao.org/qs/download/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" resolved "https://registry.npm.taobao.org/qs/download/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论