Commit d83b3ce2 authored by 高宇's avatar 高宇

完善上传接口;

parent cf4cac0e
...@@ -33,6 +33,13 @@ ...@@ -33,6 +33,13 @@
"title": "销售记录", "title": "销售记录",
"appName": 'salesOrders', "appName": 'salesOrders',
"url": "/salesOrder" "url": "/salesOrder"
},
{
"icon": "fa-contao",
"isRouteShow": 1,
"title": "销售合同",
"appName": 'salesContracts',
"url": "/salesContract"
} }
], ],
homePage: { homePage: {
......
import ElementApi from './apis/project' import ElementApi from './apis/project'
import sales from './apis/sales' import sales from './apis/sales'
import contract from './apis/contract'
const usingJSONP = process.env.NODE_ENV !== 'production' const usingJSONP = process.env.NODE_ENV !== 'production'
const API_HOST = process.env.API_HOST const API_HOST = process.env.API_HOST
const API_PORT = process.env.API_PORT const API_PORT = process.env.API_PORT
...@@ -24,8 +25,7 @@ const option = { ...@@ -24,8 +25,7 @@ const option = {
} }
let apis = {} let apis = {}
apis = Object.assign(apis, ElementApi) apis = Object.assign(apis, ElementApi, sales, contract)
apis = Object.assign(apis, sales)
export default { export default {
option, option,
...apis ...apis
......
export default {
getContractFilter: {
url: '/vue/sales-contract/get-filter'
},
getContractList: {
url: '/vue/sales-contract/list'
},
getContractClient: {
url: '/vue/sales-contract/of-client'
},
// 获取新建销售合同 option
getContractNewOptions: {
url: '/vue/sales-contract/get-new'
},
// 新建销售合同保存
saveContractAdd: {
url: '/vue/sales-contract/save-new'
},
// 获取销售合同编辑信息
getContractEdit: {
url: '/vue/sales-contract/get-edit'
},
// 销售合同编辑保存
saveContractEdit: {
url: '/vue/sales-contract/save-edit'
},
// 删除销售合同
delContract: {
url: '/vue/sales-contract/delete'
},
uploadSingle: {
url: '/vue/upload/single'
}
}
<template>
<div class="multiple-data-input">
<el-row :gutter="10">
<el-col :span="4" :class="['client-label', 'text-right', {'required': required}]">
<span>{{label}}</span>
</el-col>
<el-col :span="14">
<template v-for="(rowItem, key) in multipleDateInputItem">
<el-row :gutter="10">
<el-col :span="12">
<el-date-picker
size="mini"
v-model="rowItem.name"
type="date"
placeholder="选择日期"
format="yyyy-MM-dd"
value-format="yyyy-MM-dd">
</el-date-picker>
</el-col>
<el-col :span="12">
<el-input v-model="rowItem.value" :placeholder="inputLabel" size="mini">
<template slot="prepend">
<span v-if="prepend.text !== ''">{{prepend.text}}</span>
<i :class="['fa', prepend.icon]" v-if="prepend.icon !== ''"></i>
</template>
<el-button slot="append" v-if="key === multipleDateInputItem.length - 1" icon="el-icon-plus"
@click.prevent.stop="addDateInputItem(multipleDateInputItem)"></el-button>
<el-button slot="append" v-else icon="el-icon-minus"
@click.prevent.stop="delDateInputItem(multipleDateInputItem, key)"></el-button>
</el-input>
</el-col>
</el-row>
</template>
</el-col>
<el-col :span="6">
<slot name="formError"></slot>
<span class="tips">{{tips}}</span>
</el-col>
</el-row>
</div>
</template>
<script>
import itemMixin from '../../lib/singleItemMixin'
export default {
name: 'multiple-date-input',
mixins: [itemMixin],
data () {
return {
dateInputItems: []
}
},
methods: {
addDateInputItem (items) {
items.push({
name: '',
value: ''
})
},
delDateInputItem (items, key) {
items.splice(key, 1)
}
},
props: ['inputLabel', 'multipleDateInputItem'],
watch: {
}
}
</script>
<style scoped>
.el-select {
width: 100%;
}
</style>
<style>
.multiple-data-input .el-input-group__prepend {
padding: 4px 10px;
}
.multiple-data-input .el-input {
width: 100%;
}
</style>
<template>
<section class="multiple-date-input">
<el-row :gutter="10">
<el-col :span="4" :class="['client-label', 'text-right', {'required': required}]">
<span>{{label}}</span>
{{item}}
</el-col>
<el-col :span="14">
<span v-for="(i, key) in multipleDatePickerItem" :key="key">
<el-row :gutter="0">
<el-col :span="22">
<el-date-picker
size="mini"
v-model="i.name"
type="date"
placeholder="选择日期"
format="yyyy-MM-dd"
value-format="yyyy-MM-dd">
</el-date-picker>
</el-col>
<el-col :span="2">
<div class="multiple-button">
<el-button class="el-button el-button--default" type="primary" size="mini" icon="el-icon-plus" v-if="key === multipleDatePickerItem.length - 1" @click="addMultipleDateItem(multipleDatePickerItem)"></el-button>
<el-button class="el-button el-button--default" type="primary" size="mini" icon="el-icon-minus" v-else @click="delMultipleDateItem(multipleDatePickerItem, key)"></el-button>
</div>
</el-col>
</el-row>
<!--<el-input v-model="i[multipleKey]" :placeholder="label" size="mini">-->
<!--<template slot="prepend">{{setPerText(key)}}</template>-->
<!--<el-button slot="append" v-if="key === 0" icon="el-icon-plus" @click="addItem(items)"></el-button>-->
<!--<el-button slot="append" v-else icon="el-icon-minus" @click="delItem(items, key)"></el-button>-->
<!--</el-input>-->
</span>
</el-col>
<el-col :span="6">
<slot name="formError"></slot>
</el-col>
</el-row>
</section>
</template>
<script>
import itemMixin from '../../lib/singleItemMixin'
export default {
name: 'multiple-data-picker',
mixins: [itemMixin],
data () {
return {}
},
methods: {
addMultipleDateItem (items) {
items.push({
key: 'new',
name: ''
})
},
delMultipleDateItem (items, key) {
items.splice(key, 1)
}
},
props: ['multipleDatePickerItem'],
watch: {
multipleDatePickerItem: {
handler (val) {
console.log(val)
},
immediate: true,
deep: true
}
}
}
</script>
<style scoped>
.el-date-editor.el-input{
width: 100%;
}
</style>
<style>
.multiple-button{
line-height: 38px;
vertical-align: middle;
}
.multiple-button .el-button {
background-color: #fff!important;
border-radius: 0 4px 4px 0;
padding: 8px 15px;
}
.multiple-button .el-button i {
color: #606266;
}
.multiple-date-input .el-input--mini .el-input__inner{
border-radius: 5px 0 0 5px;
}
</style>
...@@ -32,7 +32,6 @@ ...@@ -32,7 +32,6 @@
mixins: [itemMixin], mixins: [itemMixin],
methods: { methods: {
selectChange (key) { selectChange (key) {
console.log(key)
if (this.setOption) { if (this.setOption) {
this.setOption(key) this.setOption(key)
} }
......
<template>
<div class="single-upload">
<el-row :gutter="10">
<el-col :span="4" :class="['client-label', 'text-right', {'required': required}]">
<span>{{label}}</span>
</el-col>
<el-col :span="14">
<el-upload
ref="upload"
:limit="1"
class="upload-single"
:http-request="upload"
:auto-upload="false"
list-type="text"
:multiple="false"
:before-upload="beforeUpload"
:on-remove="handleRemove"
action="/vue/upload/single"
:on-change="handleChange"
accept=".jpg,.jpeg,.png,.gif,.bmp,.pdf,.JPG,.JPEG,.PBG,.GIF,.BMP,.PDF"
:file-list="fileList">
<el-button size="small" type="primary" @click="submitUpload" :disabled="fileList.length > 0">上传到服务器
</el-button>
<el-button slot="trigger" size="small" type="primary">选择文件</el-button>
<div class="progress">
<el-progress :percentage="progress" v-if="progress > 0 && progress < 100"></el-progress>
</div>
</el-upload>
<span class="tips"><em>{{tips}}</em></span>
</el-col>
<el-col :span="6">
<slot name="formError"></slot>
</el-col>
</el-row>
</div>
</template>
<script>
import $ from 'jquery'
import { api } from '@/lib/commonMixin'
import {request} from '@/lib/request'
import itemMixin from '../../lib/singleItemMixin'
export default {
name: 'single-upload',
mixins: [itemMixin],
data () {
return {
fileList: [],
progress: 0
}
},
methods: {
beforeUpload (file, upload) {
const isLt50M = file.size / 1024 / 1024 < 50
if (!isLt50M) {
this.$message.error('上传文件大小不能超过50MB!请重新选择文件') // 上传头像图片大小不能超过 2MB
}
return isLt50M
},
handleRemove (file, fileList) {
this.fileList = fileList
this.$refs.upload.abort()
this.$refs.upload.clearFiles()
this.$emit('update:item', '')
},
progressBar (evt) {
var loaded = evt.loaded // 已经上传大小情况
var tot = evt.total // 附件总大小
var per = Math.floor(100 * loaded / tot) // 已经上传的百分比
this.progress = per // 绘制经度条
},
handleChange () {
},
submitUpload () {
this.$refs.upload.submit()
},
upload (item) {
let formData = new FormData()
formData.append('UploadForm[attachmentFile]', item.file)
let _this = this
request({
url: api.uploadSingle.url,
// url: 'http://localhost:13009/bankimage/uploadImgToBank',
type: 'POST',
cache: false,
data: formData,
contentType: false,
processData: false,
xhr () {
let xhr = $.ajaxSettings.xhr()
if (xhr.upload) {
xhr.upload.addEventListener('progress', _this.progressBar, false)
return xhr
}
}
}).then(res => {
this.progress = 95
this.fileList.push({
name: res.orig_name,
url: res.path
})
this.$emit('update:item', res.key)
}).finally(() => {
this.progress = 100
})
}
},
props: {
fileName: {
type: String,
default: ''
}
},
watch: {
fileName: {
handler (val) {
if (val !== '') {
this.fileList.push({
name: val
})
}
},
immediate: true
}
}
}
</script>
<style scoped>
.tips {
display: block;
line-height: 1.5;
color: #6c757d;
font-size: 12px;
}
</style>
<style>
.single-upload {
width: 100%;
}
.single-upload .tips {
display: block;
margin: 0
}
.single-upload .upload-single {
position: relative;
clear: both;
overflow: hidden;
}
.single-upload .progress {
position: absolute;
width: 100%;
right: 0;
bottom: -17px;
height: 15px;
box-shadow: none;
}
.single-upload .upload-single .el-upload-list--text {
height: 32px;
display: inline-block;
border: 1px solid #ffffff;
width: 100%;
border-radius: 4px;
background: #fff;
vertical-align: middle;
}
.single-upload .upload-single .el-upload {
display: inline-block;
}
.single-upload .upload-single > .el-button {
display: inline-block;
}
.single-upload .upload-single > .el-button {
vertical-align: middle;
}
.single-upload .upload-single .el-upload-list__item:first-child {
margin-top: 3px;
}
</style>
<template>
<div>
<el-row class="form-content">
<el-form ref="clientTimeRange" :model="clientTimeRange" size="mini" label-position="top">
<el-col :span="8" :xs="{span: 24, offset: 0}" class="form-content-time-top">
<el-form-item label="签订日期">
<div class="form-content-time-range">
<el-date-picker
size="mini"
v-model="clientTimeRange.from"
type="date"
value-format="yyyy-MM-dd"
placeholder="开始时间">
</el-date-picker>
<el-date-picker
size="mini"
v-model="clientTimeRange.to"
type="date"
value-format="yyyy-MM-dd"
placeholder="结束时间">
</el-date-picker>
<el-button type="primary" size="mini" @click="setSearchTime">确定</el-button>
</div>
</el-form-item>
</el-col>
</el-form>
<el-form size="mini" :model="clientForm" label-width="0" label-position="top">
<el-col :span="4" v-for="(item, key) in filter" :key="key">
<el-form-item>
<span slot="label" v-if="item.key !== 'Filter[sort]'">
<a @click.prevent="timeSort" v-if="item.key === 'Filter[name]'">
{{item.name}}
<i :class="['fa', setSortIcon()]"></i>
</a>
<span v-else>
{{item.name}}
</span>
</span>
<el-select clearable
v-model="clientForm[item.key]"
placeholder="请选择"
v-if="!item.itemKey && item.key !== 'Filter[sort]'" size="mini">
<el-option v-for="(option, optKey) in item.value"
:key="optKey"
:label="option.name"
:value="option.key">
<span style="font-size: 12px;">{{option.name}}</span>
</el-option>
</el-select>
<el-cascader
:ref="'elCasc' + key"
v-model="item.cascader"
:props="props"
clearable
change-on-select
v-if="item.itemKey"
:options="item.value"
@change="setCascader(item, key)"
></el-cascader>
</el-form-item>
</el-col>
</el-form>
</el-row>
</div>
</template>
<script>
import {findWhere} from '../../lib/viewHelper'
import $ from 'jquery'
const timeItem = ['period']
export default {
name: 'client-form',
data () {
return {
clientTimeForm: {},
clientTimeRange: {
from: '',
to: ''
},
clientForm: {},
props: {
label: 'name',
value: 'key',
children: 'child'
}
}
},
props: ['filter', 'formSearchKey'],
methods: {
setCascader (item, key) {
if (item.cascader.length === 1) {
this.clientForm[item.key] = item.cascader[0]
this.clientForm[item.itemKey] = ''
} else if (item.cascader.length === 2) {
this.clientForm[item.itemKey] = item.cascader[0]
this.clientForm[item.key] = item.cascader[1]
} else {
this.clientForm[item.itemKey] = ''
this.clientForm[item.key] = ''
}
},
setDefault (filter) {
filter.forEach(item => {
if (item.default) {
let keys = findWhere(item.value, item.default, 'key')
if (keys.node) {
if (keys.parentNode) {
this.clientForm[item.itemKey] = keys.parentNode.key
this.clientForm[item.key] = keys.node.key
item.cascader = [keys.parentNode.key, keys.node.key]
} else {
this.clientForm[item.itemKey] = ''
this.clientForm[item.key] = keys.node.key
item.cascader = [keys.node.key]
}
}
}
})
},
init (isCascader) {
this.$watch('clientForm', (val) => {
this.$emit('update:clientList', Object.assign({}, val, this.clientTimeForm))
}, {deep: true})
this.$watch('clientTimeForm', (val) => {
let perid = val[this.formSearchKey + '[period]']
this.$emit('update:clientList', Object.assign({}, {[this.formSearchKey + '[period]']: perid}, this.clientForm))
}, {deep: true})
let _this = this
if (isCascader) {
$(document).ready(() => {
$(document).on('mouseleave', '.el-cascader-menus', () => {
Object.keys(_this.$refs).forEach(item => {
_this.$refs[item][0].menuVisible = false
})
})
})
}
},
setSortIcon () {
if (this.clientForm['Filter[sort]'] === '') {
return 'fa-sort-amount-desc'
} else if (this.clientForm['Filter[sort]'] === 'DESC') {
return 'fa-sort-amount-desc'
} else {
return 'fa-sort-amount-asc'
}
},
timeSort () {
if (this.clientForm['Filter[sort]'] === '') {
this.clientForm['Filter[sort]'] = 'ASC'
} else if (this.clientForm['Filter[sort]'] === 'ASC') {
this.clientForm['Filter[sort]'] = 'DESC'
} else {
this.clientForm['Filter[sort]'] = 'ASC'
}
},
setSearchTime () {
let from = this.clientTimeRange.from
let to = this.clientTimeRange.to
this.$emit('update:clientList', Object.assign({}, {
[this.formSearchKey + '[from]']: from,
[this.formSearchKey + '[to]']: to
}, this.clientTimeForm, this.clientForm))
}
},
mounted () {
},
watch: {
'clientTimeRange.from' (val) {
if (new Date(val) >= new Date(this.clientTimeRange.to)) {
this.clientTimeRange.to = val
}
if (this.clientTimeRange.to === '') {
this.clientTimeRange.to = val
}
},
'clientTimeRange.to' (val) {
if (new Date(val) <= new Date(this.clientTimeRange.from)) {
this.clientTimeRange.from = val
}
if (this.clientTimeRange.from === '') {
this.clientTimeRange.from = val
}
},
'filter' (val) {
let isCascader = false
val.forEach(item => {
if (item.itemKey) {
this.$set(this.clientForm, item.itemKey, '')
this.$set(item, 'cascader', [])
isCascader = true
}
this.$set(this.clientForm, item.key, '')
})
this.$nextTick(() => {
this.init(isCascader)
this.setDefault(val)
})
},
'formSearchKey': {
handler (val) {
if (val !== '') {
timeItem.forEach(item => {
this.$set(this.clientTimeForm, val + '[' + item + ']', '')
})
}
},
immediate: true
}
}
}
</script>
<style scoped>
.form-content-time-top {
background: #FFF;
}
.form-content-time-top .el-form-item {
margin: 7px 0 9px;
}
.form-content-time-top .el-col {
padding: 0 15px;
}
</style>
<style>
.form-content .el-form-item__label {
font-size: 12px;
font-weight: normal;
padding: 0 2px 0 0;
}
.form-content-time-top .el-radio-button__orig-radio:checked + .el-radio-button__inner {
color: #fff !important;
background-color: #333744 !important;
border-color: #282b35 !important;
box-shadow: -1px 0 0 0 #282b35;
}
.form-content-time-top .el-radio-button:first-child .el-radio-button__inner {
border-left: 1px solid #DCDFE6;
}
.form-content-time-top .el-radio-button__inner:hover {
border-color: #DCDFE6 !important;
}
.form-content-time-top .el-form-item .el-form-item__content .form-content-time-range{
display: flex;
font-size: 12px;
}
</style>
<template>
<section>
<div class="content">
<client-header ref="clientHeader"
:title="'客户名称:' + model.name"
:title-span="12"
type=""></client-header>
<div class="page-body-content">
<client-nav :trigger="addContract" trigger-text="新建销售合同"></client-nav>
<div v-loading="loading">
<ScheduleItem
v-for="(item, key) in result.list"
:item="item"
:key="key"
@update:image="imgs => {setImage(imgs)}"
@update:showProject="project => {showProject(project)}">
<span slot="opearate">
<el-button class="pull-right"
type="primary"
size="mini"
:disabled="!item.can_delete"
@click="delContract(item.id)">
<i class="fa fa-trash-o faa-shake"></i> 删除
</el-button>
<el-button class="pull-right"
type="primary"
size="mini"
:disabled="!item.can_update"
@click.prevent.stop="editContract(item)">
<i class="fa fa-edit"></i> 编辑
</el-button>
<el-button class="pull-right"
type="primary"
size="mini"
@click.prevent.stop="leaveMessageSch(item)">
<span :class="['badge', {'badge-unread': item.unread > 0}]"
v-if="item.commentCount">{{item.commentCount.comment}}</span>
<i class="fa fa-commenting"></i> 留言
</el-button>
</span>
</ScheduleItem>
<div v-if="result.list.length === 0">
<el-card class="box-card">
未查询到数据!
</el-card>
</div>
</div>
<Pagenation
@update:pager="pager => {updatePage(pager)}"
:pager.sync="pagenation"
:total="totalcount">
</Pagenation>
<leave-message
v-click-outside="lmClose"
ref="leaveMessage"
:lmTemplate="lmTemplate"
:type="1">
</leave-message>
</div>
</div>
<side-popup ref="sidePopup" :title="operationTitle" v-click-outside="popupClose">
<component :is="operationPage" :ref="operationPage" @close="getList => {close(getList)}"></component>
</side-popup>
</section>
</template>
<script>
import ScheduleItem from '../scheduleItem'
import clientHeader from '../../common/clientHeader'
import Pagenation from '../../common/schedulePagenation'
import clickOutside from '@/lib/bind'
import addContract from '../operation/addContract'
import editContract from '../operation/editContract'
import viewProject from '../operation/viewProject'
import {
requestAPI,
api
} from '@/lib/commonMixin'
export default {
name: '',
directives: {
clickOutside
},
data () {
return {
lmTemplate: [
{
name: '客户名称',
value: 'client.name',
default: ''
},
{
name: '合同类型',
value: 'contractType',
default: ''
},
{
name: '总额',
value: 'amount',
default: '',
prepend: '¥'
},
{
name: '客户经理',
value: 'salesRep',
default: ''
},
{
name: '录入人',
value: 'createdUser',
default: ''
},
{
name: '签订日期',
value: 'signed_at',
default: ''
}
],
operationPage: '',
operationTitle: '',
clientName: '',
model: {
name: ''
},
result: {
list: []
},
pagenation: {
page: 1
},
totalcount: 0,
loading: false
}
},
components: {
ScheduleItem,
clientHeader,
Pagenation,
addContract,
editContract,
viewProject
},
methods: {
showProject (project) {
this.operationPage = 'viewProject'
this.operationTitle = '商机信息'
requestAPI(api.getProjectEdit, {
data: {
id: project.key
}
}).then(res => {
this.$refs.sidePopup.show(this.$refs[this.operationPage].init(res))
})
},
addContract () {
this.operationPage = 'addContract'
this.operationTitle = '新建销售合同'
this.$nextTick(() => {
this.$refs.sidePopup.show(this.$refs[this.operationPage].init())
})
},
editContract (row) {
this.operationPage = 'editContract'
this.operationTitle = '编辑销售合同'
this.$nextTick(() => {
this.$refs.sidePopup.show(this.$refs[this.operationPage].init(row.id))
})
},
close (getList) {
this.$refs.sidePopup.close()
if (getList) {
this.getList()
}
},
leaveMessageSch (item) {
this.$refs.leaveMessage.btnShow(item)
},
lmClose () {
this.$refs.leaveMessage &&
this.$refs.leaveMessage.btnClose()
},
popupClose () {
this.$refs.sidePopup &&
this.$refs.sidePopup.close()
},
getList () {
if (this.loading) {
return
}
this.loading = true
requestAPI(api.getContractList, {
data: {
id: this.$route.params.id,
page: this.pagenation.page
}
}).then(res => {
this.result.list = res.list
// this.pagenation.page = res.pagenation.thispage
this.totalcount = res.pagenation.totalcount
// this.totalcount = 8
this.$el.querySelector('.page-body-content').scrollTo(0, 0)
}).finally(_ => {
this.loading = false
})
}
},
created () {
requestAPI(api.getClient, {
data: {
id: this.$route.params.id
}
}).then(res => {
Object.keys(res.model).forEach(item => {
this.$set(this.model, item, res.model[item])
})
this.getList()
}, error => {
if (Array.isArray(error.msg)) {
error.msg.forEach(item => {
this.$notify.error({
title: '错误',
message: item.error
})
})
}
})
}
}
</script>
<style scoped lang="scss">
@include c('schedule-right') {
> .el-row {
> .el-col {
margin-bottom: 4px;
.el-button {
margin: 0 2px;
padding: 7px;
}
.date-time {
color: #649FD7;
}
}
}
.badge {
border-radius: 2px;
color: #333744;
background: #ffffff;
vertical-align: baseline;
display: inline;
padding: 2px 6px;
}
span.badge-unread {
&:hover {
border-color: #de321d
}
color: #fff;
background-color: #e54c3a;
border-color: #a32516
}
}
</style>
<template>
<section>
<div class="content">
<client-header ref="clientHeader"
title="销售合同"
:title-span="6"
:model="form"
search-key="SalesContractSearch"
key-code="keyword"
type="keyword"
button-title="新建销售合同 "
:add-new-user="addNewContract"
:search-keyword="searchKeyword"></client-header>
<client-form ref="clientForm"
:filter="filter"
@update:clientList="form =>{ updateForm(form)}"
:form-search-key="formSearchKey"></client-form>
<div class="page-body-content">
<div v-loading="loading">
<ScheduleItem
v-for="(item, key) in result.list"
:item="item"
:key="key"
@update:image="imgs => {setImage(imgs)}"
@update:showProject="project => {showProject(project)}">
<span slot="opearate">
<el-button class="pull-right"
type="primary"
size="mini"
:disabled="!item.can_delete"
@click="delContract(item.id)">
<i class="fa fa-trash-o faa-shake"></i> 删除
</el-button>
<el-button class="pull-right"
type="primary"
size="mini"
:disabled="!item.can_update"
@click.prevent.stop="editContract(item)">
<i class="fa fa-edit"></i> 编辑
</el-button>
<el-button class="pull-right"
type="primary"
size="mini"
@click.prevent.stop="leaveMessageSch(item)">
<span :class="['badge', {'badge-unread': item.unread > 0}]"
v-if="item.commentCount">{{item.commentCount.comment}}</span>
<i class="fa fa-commenting"></i> 留言
</el-button>
</span>
</ScheduleItem>
<div v-if="result.list.length === 0">
<el-card class="box-card">
未查询到数据!
</el-card>
</div>
</div>
<Pagenation
@update:pager="pager => {updatePage(pager)}"
:pager.sync="pagenation"
:total="totalcount">
</Pagenation>
<leave-message
v-click-outside="lmClose"
ref="leaveMessage"
:lmTemplate="lmTemplate"
:type="1">
</leave-message>
</div>
</div>
<side-popup ref="sidePopup" :title="operationTitle" v-click-outside="popupClose">
<component :is="operationPage" :ref="operationPage" @close="getList => {close(getList)}"></component>
</side-popup>
</section>
</template>
<script>
import clientHeader from '../common/clientHeader'
import clickOutside from '@/lib/bind'
import Pagenation from '../common/schedulePagenation'
import clientForm from './contractListForm'
import ScheduleItem from './scheduleItem'
import viewProject from './operation/viewProject'
import addContract from './operation/addContract'
import editContract from './operation/editContract'
import {
requestAPI,
api
} from '@/lib/commonMixin'
export default {
name: '',
components: {
clientHeader,
clientForm,
Pagenation,
ScheduleItem,
viewProject,
addContract,
editContract
},
directives: {
clickOutside
},
data () {
return {
lmTemplate: [
{
name: '客户名称',
value: 'client.name',
default: ''
},
{
name: '合同类型',
value: 'contract_type',
default: '',
data: ['产品销售', '运维服务']
},
{
name: '总额',
value: 'amount',
default: '',
prepend: '¥'
},
{
name: '客户经理',
value: 'client.salesRep.name',
default: ''
},
{
name: '录入人',
value: 'createdBy.name',
default: ''
},
{
name: '签订日期',
value: 'signed_at',
default: ''
}
],
operationPage: '',
operationTitle: '',
result: {
list: []
},
form: {
'SalesContractSearch[keyword]': ''
},
filter: [],
pagenation: {
page: 1
},
totalcount: 0,
loading: false,
formSearchKey: 'SalesContractSearch'
}
},
methods: {
showProject (project) {
this.operationPage = 'viewProject'
this.operationTitle = '商机信息'
requestAPI(api.getProjectEdit, {
data: {
id: project.key
}
}).then(res => {
this.$refs.sidePopup.show(this.$refs[this.operationPage].init(res))
})
},
close (getList) {
this.$refs.sidePopup &&
this.$refs.sidePopup.close()
if (getList) {
this.getList()
}
},
leaveMessageSch (item) {
this.$refs.leaveMessage.btnShow(item)
// console.log(this.$el.querySelector())
},
lmClose () {
this.$refs.leaveMessage &&
this.$refs.leaveMessage.btnClose()
},
popupClose () {
this.$refs.sidePopup &&
this.$refs.sidePopup.close()
},
searchKeyword (search) {
this.updateForm(search)
},
delSales (id) {
this.$confirm('确认删除吗?', '提示').then(() => {
requestAPI(api.delContract, {
data: {
id
}
}).then(() => {
this.$message('删除成功!')
this.getList()
}, error => {
if (Array.isArray(error.msg)) {
error.msg.forEach(item => {
this.$notify.error({
title: '错误',
message: item.error
})
})
}
})
}).catch(_ => {
})
},
addNewContract () {
this.operationPage = 'addContract'
this.operationTitle = '新建销售合同'
this.$nextTick(() => {
this.$refs.sidePopup.show(this.$refs[this.operationPage].init())
})
},
editContract (row) {
this.operationPage = 'editContract'
this.operationTitle = '编辑销售合同'
this.$nextTick(() => {
this.$refs.sidePopup.show(this.$refs[this.operationPage].init(row.id))
})
},
updateForm (form) {
Object.assign(this.form, form)
this.getList()
},
resetListData (list) {
// ['产品销售', '运维服务'][parseInt(item.contract_type) - 1]
list.forEach(item => {
item.contractType = ['产品销售', '运维服务'][parseInt(item.contract_type) - 1]
if (Object.keys(item.client.salesRep).length > 0) {
item.salesRep = item.client.salesRep.name
} else {
item.salesRep = '(未设置)'
}
if (Object.keys(item.createdBy).length > 0) {
item.createdUser = item.createdBy.name
} else {
item.createdUser = '(未设置)'
}
})
return list
},
getList () {
if (this.loading) {
return
}
this.loading = true
requestAPI(api.getContractList, {
data: {
...this.form,
page: this.pagenation.page
}
}).then(res => {
this.result.list = this.resetListData(res.list)
// this.pagenation.page = res.pagenation.thispage
this.totalcount = res.pagenation.totalcount
// this.totalcount = 8
this.$el.querySelector('.page-body-content').scrollTo(0, 0)
}).finally(_ => {
this.loading = false
})
},
getFilter () {
requestAPI(api.getContractFilter).then(res => {
this.filter = res
})
}
},
created () {
this.getFilter()
this.$nextTick(() => {
this.getList()
})
}
}
</script>
<style scoped lang="scss">
@include c('schedule-right') {
> .el-row {
> .el-col {
margin-bottom: 4px;
.el-button {
margin: 0 2px;
padding: 7px;
}
.date-time {
color: #649FD7;
}
}
}
.badge {
border-radius: 2px;
color: #333744;
background: #ffffff;
vertical-align: baseline;
display: inline;
padding: 2px 6px;
}
span.badge-unread {
&:hover {
border-color: #de321d
}
color: #fff;
background-color: #e54c3a;
border-color: #a32516
}
}
</style>
<template>
<section>
<operation-contract
ref="operationContract"
type="add"
:error-data="errorData">
<span slot="operationBtn">
<el-button type="primary" @click="saveContract" size="mini">保存</el-button>
<el-button @click="close()" size="mini">关闭</el-button>
</span>
</operation-contract>
</section>
</template>
<script>
// import {
// requestAPI,
// api
// } from '@/lib/commonMixin'
import operationContract from './operationContract'
// import {setModule} from '../../../lib/viewHelper'
export default {
name: '',
components: {
operationContract
},
data () {
return {
errorData: {}
}
},
methods: {
saveContract () {
let form = this.$refs.operationContract.getForm()
console.log(form)
},
close (getList) {
this.$emit('close', getList)
},
init () {
this.$refs.operationContract.initAdd()
}
},
created () {
}
}
</script>
<style scoped>
</style>
<template>
<section>
<operation-contract
ref="operationContract"
type="edit"
:error-data="errorData">
<span slot="operationBtn">
<el-button type="primary" @click="saveContract" size="mini">保存</el-button>
<el-button @click="close()" size="mini">关闭</el-button>
</span>
</operation-contract>
</section>
</template>
<script>
// import {
// requestAPI,
// api
// } from '@/lib/commonMixin'
import operationContract from './operationContract'
// import {setModule} from '../../../lib/viewHelper'
export default {
name: '',
components: {
operationContract
},
data () {
return {
errorData: {}
}
},
methods: {
saveContract () {},
close (getList) {
this.$emit('close', getList)
},
init (id) {
this.$refs.operationContract.initEdit(id)
}
},
created () {
}
}
</script>
<style scoped>
</style>
<template>
<div class="contract-add-edit-form auto-template-form">
<el-form ref="form" :model="SalesContracts">
<el-form-item :show-message="false" :error="setError('client_id')">
<single-search-input
:form-serch-item="SalesContracts.client_id"
:form-show-text="searchText"
:set-option="setClientOption"
api="searchClientByName"
label="客户名称"
:single-search-disabled="singleSearchDisabled"
@update:searchItem="val => {SalesContracts.client_id = val}">
<span slot="formError" class="el-form-item__error">
{{errorData['client_id']}}
</span>
</single-search-input>
</el-form-item>
<el-form-item :show-message="false" :error="setError('project_id')">
<single-select
:form-item="SalesContracts.project_id"
label="项目名称"
:options-list="getOptions('SalesContracts[project_id]')"
@update:item="val => {SalesContracts.project_id = val}">
<span slot="formError" class="el-form-item__error">
{{errorData['project_id']}}
</span>
</single-select>
</el-form-item>
<el-form-item :show-message="false" :error="setError('serial_no')">
<single-input
label="序列号"
:required="true"
:form-item="SalesContracts.serial_no"
@update:item="val => {SalesContracts.serial_no = val}">
<span slot="formError" class="el-form-item__error">
{{errorData['serial_no']}}
</span>
</single-input>
</el-form-item>
<el-form-item :show-message="false" :error="setError('contract_type')">
<!--clientFrom-->
<single-radio
:form-item="SalesContracts.contract_type"
label="合同类型"
:required="true"
:options-list="getOptions('SalesContracts[contract_type]')"
@update:item="val => {SalesContracts.contract_type = val}">
<span slot="formError" class="el-form-item__error">
{{errorData['contract_type']}}
</span>
</single-radio>
</el-form-item>
<el-form-item :show-message="false" :error="setError('signed_at')">
<single-date-picker
:form-time-item="SalesContracts.signed_at"
label="签订日期"
@update:item="val => {SalesContracts.signed_at = val}">
<span slot="formError" class="el-form-item__error">
{{errorData['signed_at']}}
</span>
</single-date-picker>
</el-form-item>
<el-form-item :show-message="false" :error="setError('amount')">
<single-input
label="合同总额"
:form-item="SalesContracts.amount"
@update:item="val => {SalesContracts.amount = val}">
<span slot="formError" class="el-form-item__error">
{{errorData['amount']}}
</span>
</single-input>
</el-form-item>
<el-form-item :show-message="false" :error="errorData['description'] ? errorData['description'] : ''">
<single-input
label="备注"
:required="true"
type="textarea"
:rows="4"
:form-item="SalesContracts.description"
@update:item="val => {SalesContracts.description = val}">
<span slot="formError" class="el-form-item__error">
{{errorData['description']}}
</span>
</single-input>
</el-form-item>
<el-form-item :show-message="false" :error="errorData['contract_scan'] ? errorData['contract_scan'] : ''">
<single-upload
label="上传合同"
tips="只能上传 jpg,png,pdf 类型文件, 文件不能超过50M, 当有新文件上传时, 之前上传的文件将会被删除"
:form-item="SalesContracts.contract_scan"
:file-name="getFileName('contractScan')"
@update:item="val => {SalesContracts.contract_scan = val}">
<span slot="formError" class="el-form-item__error">
{{errorData['contract_scan']}}
</span>
</single-upload>
</el-form-item>
<el-form-item :show-message="false" :error="errorData['receipt_scan'] ? errorData['receipt_scan'] : ''">
<single-upload
label="上传签收单"
:file-name="getFileName('receiptScan')"
tips="只能上传 jpg,png,pdf 类型文件, 文件不能超过50M, 当有新文件上传时, 之前上传的文件将会被删除"
:form-item="SalesContracts.receipt_scan"
@update:item="val => {SalesContracts.receipt_scan = val}">
<span slot="formError" class="el-form-item__error">
{{errorData['receipt_scan']}}
</span>
</single-upload>
</el-form-item>
<el-form-item :show-message="false" :error="setError('expire_date')">
<single-date-picker
:form-time-item="SalesContracts.expire_date"
label="服务截止日期"
@update:item="val => {SalesContracts.expire_date = val}">
<span slot="formError" class="el-form-item__error">
{{errorData['expire_date']}}
</span>
</single-date-picker>
</el-form-item>
<el-form-item :show-message="false" :error="setError('expire_remind_ahead')">
<single-select
:form-item="SalesContracts.expire_remind_ahead"
label="过期提醒时间"
:options-list="getOptions('SalesContracts[expire_remind_ahead]')"
@update:item="val => {SalesContracts.expire_remind_ahead = val}">
<span slot="formError" class="el-form-item__error">
{{errorData['expire_remind_ahead']}}
</span>
</single-select>
</el-form-item>
<el-form-item :show-message="false" :error="setError('salesContractRemindReceivers')">
<multiple-check-group
:check-group-form-item="SalesContracts.salesContractRemindReceivers"
label="过期提醒人"
:check-group-options-list="getOptions('SalesContracts[salesContractRemindReceivers]')"
@update:item="val => {SalesContracts.salesContractRemindReceivers = val}">
<span slot="formError" class="el-form-item__error">
{{errorData['salesContractRemindReceivers']}}
</span>
</multiple-check-group>
</el-form-item>
<el-form-item :show-message="false" :error="setError('salesContractPaymentCollectionRemindDates')">
<!--<multiple-date-input-->
<!--label="回款日期及金额"-->
<!--:multiple-date-input-item="SalesContracts.salesContractPaymentCollectionRemindDates"-->
<!--:prepend="{icon: 'fa-yen'}"-->
<!--@update:item="val => {SalesContracts.salesContractPaymentCollectionRemindDates = val}">-->
<!--<span slot="formError" class="el-form-item__error">-->
<!--{{errorData['salesContractPaymentCollectionRemindDates']}}-->
<!--</span>-->
<!--</multiple-date-input>-->
<multiple-date-input
label="回款日期及金额"
:multiple-date-input-item="SalesContracts.salesContractPaymentCollectionRemindDates"
:prepend="{icon: 'fa-yen'}"
@update:item="val => {SalesContracts.salesContractPaymentCollectionRemindDates = val}">
<span slot="formError" class="el-form-item__error">
{{errorData['salesContractPaymentCollectionRemindDates']}}
</span>
</multiple-date-input>
<!--{{SalesContracts.salesContractPaymentCollectionRemindDates}}-->
</el-form-item>
<el-form-item :show-message="false" :error="setError('payment_collection_remind_ahead')">
<single-select
:form-item="SalesContracts.payment_collection_remind_ahead"
label="回款提醒时间"
:options-list="getOptions('SalesContracts[payment_collection_remind_ahead]')"
@update:item="val => {SalesContracts.payment_collection_remind_ahead = val}">
<span slot="formError" class="el-form-item__error">
{{errorData['payment_collection_remind_ahead']}}
</span>
</single-select>
</el-form-item>
<el-form-item :show-message="false" :error="setError('salesContractPaymentCollectionRemindReceivers')">
<multiple-check-group
:check-group-form-item="SalesContracts.salesContractPaymentCollectionRemindReceivers"
label="回款提醒人"
:check-group-options-list="getOptions('SalesContracts[salesContractPaymentCollectionRemindReceivers]')"
@update:item="val => {SalesContracts.salesContractPaymentCollectionRemindReceivers = val}">
<span slot="formError" class="el-form-item__error">
{{errorData['salesContractPaymentCollectionRemindReceivers']}}
</span>
</multiple-check-group>
</el-form-item>
<el-form-item :show-messsge="false" :error="setError('sla')" v-show="SalesContracts.contract_type === 2">
<single-input
label="SLA"
:form-item="SalesContracts.sla"
@update:item="val => {SalesContracts.sla = val}">
<span slot="formError" class="el-form-item__error">
{{errorData['sla']}}
</span>
</single-input>
</el-form-item>
<el-form-item :show-message="false" :error="setError('serviceContractRemindDates')"
v-show="SalesContracts.contract_type === 2">
<multiple-date-picker
label="巡检提醒日期"
:multiple-date-picker-item="SalesContracts.serviceContractRemindDates">
<span slot="formError" class="el-form-item__error">
{{errorData['serviceContractRemindDates']}}
</span>
</multiple-date-picker>
</el-form-item>
<el-form-item :show-message="false" :error="setError('remind_date')" v-show="SalesContracts.contract_type === 2">
<single-select
:form-item="SalesContracts.remind_date"
label="提醒时间"
:options-list="getOptions('SalesContracts[remind_date]')"
@update:item="val => {SalesContracts.remind_date = val}">
<span slot="formError" class="el-form-item__error">
{{errorData['remind_date']}}
</span>
</single-select>
</el-form-item>
<el-form-item :show-message="false" :error="setError('serviceContractRemindReceivers')"
v-show="SalesContracts.contract_type === 2">
<multiple-check-group
:check-group-form-item="SalesContracts.serviceContractRemindReceivers"
label="提醒人"
:check-group-options-list="getOptions('SalesContracts[serviceContractRemindReceivers]')"
@update:item="val => {SalesContracts.serviceContractRemindReceivers = val}">
<span slot="formError" class="el-form-item__error">
{{errorData['serviceContractRemindReceivers']}}
</span>
</multiple-check-group>
</el-form-item>
<el-form-item>
<el-row :gutter="10">
<el-col :offset="4" :span="14">
<slot name="operationBtn">
</slot>
<!--<el-button type="primary" @click="test">测试</el-button>-->
</el-col>
</el-row>
</el-form-item>
</el-form>
</div>
</template>
<script>
import {
requestAPI,
api
} from '@/lib/commonMixin'
import operationMixins from '../../../lib/operationMixins'
export default {
name: '',
mixins: [operationMixins],
data () {
return {
SalesContracts: {
id: '',
client_id: '',
signed_at: '',
amount: [],
remind_date: [],
description: '',
contract_scan: '',
receipt_scan: '',
contract_type: 2,
project_id: '',
// 服务截止
expire_date: '',
expire_remind_ahead: '',
salesContractRemindReceivers: [],
// 回款
salesContractPaymentCollectionRemindDates: [{
name: '',
value: ''
}],
payment_collection_remind_ahead: '',
salesContractPaymentCollectionRemindReceivers: [],
// sla
sla: '',
serviceContractRemindDates: [
{
key: 'new',
name: ''
}
],
remind_ahead: '',
serviceContractRemindReceivers: [],
serial_no: ''
},
singleSearchDisabled: false,
options: {
'SalesContracts[project_id]': {
value: []
},
'SalesContracts[contract_type]': {
value: [
{
key: 1,
name: '产品销售'
},
{
key: 2,
name: '运维服务'
}
]
},
'SalesContracts[expire_remind_ahead]': {
value: []
},
'SalesContracts[payment_collection_remind_ahead]': {
value: []
},
'SalesContracts[remind_ahead]': {
value: []
},
// 回款提醒人
'SalesContracts[salesContractPaymentCollectionRemindReceivers]': {
value: []
},
// 过期提醒人
'SalesContracts[salesContractRemindReceivers]': {
value: []
},
// sla 提醒人
'SalesContracts[serviceContractRemindReceivers]': {
value: []
}
},
files: {
contractScan: {
name: ''
},
receiptScan: {
name: ''
}
},
client: {},
searchText: '',
pageType: '',
optionsKey: 'SalesContracts'
}
},
methods: {
setMultipleDateInputData (val) {
console.log(val)
},
getFileName (key) {
return this.files[key].name
},
getOptions (key) {
let option = {}
if (key.indexOf('[') !== -1 && key.indexOf(']') !== -1) {
option = this.options[key]
} else {
option = this.options[this.optionsKey + '[' + key + ']']
}
if (option) {
return option.value
}
return []
},
setClientOption (id) {
requestAPI(api.searchProjectByClientId, {
data: {
client_id: id
}
}).then(res => {
this.options['SalesContracts[project_id]'].value = res
})
},
setError (error) {
return this.errorData[error] ? this.errorData[error] : ''
},
getForm () {
return {SalesContracts: this.SalesContracts}
},
setFilesName (model) {
Object.keys(this.files).forEach(item => {
this.files.name = model[item].orig_name
})
},
initAdd () {
requestAPI(api.getContractNewOptions).then(res => {
Object.keys(res.options).forEach(key => {
console.log(this.options[key], key)
// res.options[key].value.forEach(i => {
// this.options[key].value.push(i)
// })
})
})
},
initEdit (id) {
requestAPI(api.getContractEdit, {
data: {
id
}
}).then(res => {
Object.keys(res.options).forEach(key => {
this.$set(this.options, key, res.options[key])
})
Object.keys(this.SalesContracts).forEach(item => {
this.SalesContracts[item] = res.model[item]
})
})
}
},
props: ['errorData'],
watch: {
'SalesContracts.contract_type' (val) {
}
}
}
</script>
<style lang="scss">
.auto-template-form {
.el-form-item {
margin-bottom: 15px;
}
.client-label {
position: relative;
font-size: 12px;
}
.client-label span {
padding-right: 10px;
}
.client-label.required:after {
content: "*";
color: #eb7567;
position: absolute;
top: 3px;
right: 6px;
}
.el-form-item__error {
position: static;
}
}
</style>
<template>
<section class="view-project">
<el-table
:data="tableData"
border
stripe
style="width: 100%"
:show-header="false">
<el-table-column
prop="title"
min-width="25%">
<template slot-scope="scope">
<b>{{scope.row.title}}</b>
</template>
</el-table-column>
<el-table-column
prop="value"
min-width="75%">
<template slot-scope="scope">
<a @click="toView(scope.row.client_id)" v-if="scope.row.toView">{{scope.row.value}}
</a>
<span :class="setClass(scope.row)" v-else>{{scope.row.value}}</span>
</template>
</el-table-column>
</el-table>
</section>
</template>
<script>
export default {
name: '',
data () {
return {
tableData: [
{
title: '客户名称',
value: '',
key: 'client.name',
toView: true,
client_id: ''
},
{
title: '项目名称',
value: '',
key: 'project_title'
},
{
title: '商机金额',
value: '',
key: 'budget',
prepend: '¥'
},
{
title: '未回款金额',
value: '',
key: 'collected',
style: true,
prepend: '¥'
},
{
title: '未开发票',
value: '',
key: 'issued_invoices',
style: true,
prepend: '¥'
},
{
title: '利润率',
value: '',
key: 'projectStatus.name'
},
{
title: '商机类型',
value: '',
key: 'projectTags'
},
{
title: '商机状态',
value: '',
key: 'projectStatus.name'
},
{
title: '销售阶段',
value: '',
key: 'projectProgress.name'
},
{
title: '销售预测',
value: '',
key: 'salesForecast.name'
},
{
title: '合同类型',
value: '',
key: 'contract_type_display'
},
{
title: '采购方式',
value: '',
key: 'purchaseType.name'
},
{
title: '商机来源',
value: '',
key: 'opportunityFrom.name'
},
{
title: '阶段停留',
value: '',
key: 'remain_display'
},
{
title: '成交日期',
value: '',
key: 'bargain_date'
},
{
title: '客户经理',
value: '',
key: 'salesRep.name'
},
{
title: '售前支持',
value: '',
key: 'projectArchitects',
type: 'array'
},
{
title: '商机内容',
value: '',
key: 'description'
},
{
title: '商机批注',
value: '',
key: 'comment',
type: 'html'
},
{
title: '更新时间',
value: '',
key: 'updated_at'
}
]
}
},
methods: {
init (data) {
this.setTableData(data.model)
},
setClass (row) {
if (row.style) {
if (parseInt(row.value.split('¥')[1]) > 0) {
return ['text-danger']
}
}
},
setTableData (model) {
this.tableData.forEach(item => {
// console.log(this.getObjByPath(model, item.key, {}), item.title)
let val = this.getObjByPath(model, item.key, {prepend: item.prepend})
// console.log(val, item.title, item.key)
if (val.indexOf('undefined') === -1) {
item.value = val
} else {
item.value = '(未设置)'
}
if (item.type === 'array') {
if (model[item.key].length > 0) {
item.value = model[item.key].map(i => i.name + i.value * 100 + '%').join(' ')
} else {
item.value = '(未设置)'
}
}
if (item.toView) {
item.client_id = model.client_id
}
})
// console.log(this.tableData)
},
getObjByPath (obj, path, option) {
let names = path.split('.')
let firstName = names.shift()
let member = obj[firstName]
let prepend = option.prepend ? option.prepend : ''
let append = option.append ? option.append : ''
if (Array.isArray(member)) {
return prepend + member.map(i => i.name).join(',') + append
}
if (member && names.length) {
return this.getObjByPath(member, names.join('.'), option)
}
return prepend + member + append
},
toView (id) {
this.$router.push({
app: 'client',
name: 'viewClient',
params: {
id
}
})
// console.log(obj)
}
},
created () {
}
}
</script>
<style>
.view-project .el-table td, .view-project .el-table th{
padding: 4px 0;
font-size: 12.25px;
}
</style>
<template>
<section class="client-schedule-item">
<el-row class="client-schedule-row">
<el-col :span="4" :xs="24" class="client-schedule-left" :style="{'background-color': item.bgcolor}">
<el-row :gutter="10">
<el-col :span="24" class="entity-name">
<i class="fa fa-fw fa-star" aria-hidden="true"></i>
<a @click="toView(item)" v-if="Object.keys(item.client).length > 0">&nbsp;{{ item.client.name }}
</a>
<span v-else>客户名称{{noneText}}</span>
</el-col>
<el-col :span="12" class="entity-name" v-if="Object.keys(item.createdBy).length > 0">
<img class="user-avatar rounded-circle" :src="item.createdBy.avatar.name">
<span class="black">{{ item.createdBy.name }}</span>
</el-col>
<el-col :span="12" v-else><i class="fa fa-fw fa-user"></i> {{noneText}}
</el-col>
</el-row>
</el-col>
<el-col :span="20" :xs="24" class="client-schedule-right">
<el-row :gutter="10">
<el-col :span="6" :xs="24" class="show-picture">
合同编号:
<span>
{{item.serial_no !== '' ? item.serial_no : noneText}}
</span>
</el-col>
<el-col :span="6" :xs="24">
<span class="border border-info text-info rounded px-1">总额</span> :
{{item.amount !== '' ? item.amount : noneText}}
</el-col>
<el-col :span="6" :xs="24">
客户经理: {{item.salesRep}}
</el-col>
<el-col :span="6" :xs="24">
签订日期: <span class="date-time">{{item.signed_at !== '' ? item.signed_at : noneText}}</span>
</el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="6" :xs="24">
项目名称:
<a href="javascript:;" size="mini" @click.prevent.stop="showProject(item.project)" v-if="Object.keys(item.project).length > 0">
{{Object.keys(item.project).length > 0 ? item.project.name : noneText}}
</a>
<span v-else>{{noneText}}</span>
</el-col>
<el-col :span="6" :xs="24">
合同类型:
<span class="border border-info text-info rounded px-1"
v-if="item.contract_type !== ''">{{['产品销售', '运维服务'][parseInt(item.contract_type) - 1]}}</span>
<span v-else>{{noneText}}</span>
</el-col>
<el-col :span="6" :xs="24">
上传合同:
<a :href="getScanUrl(item, 'contractScan')" target="_blank" v-if="Object.keys(item.contractScan).length > 0">
<i class="fa fa-fw fa-file-pdf-o"></i>
</a>
<span v-else class="text-danger">扫描件待上传</span>
</el-col>
<el-col :span="6" :xs="24">
上传签收单:
<a :href="getScanUrl(item, 'receiptScan')" target="_blank" v-if="Object.keys(item.receiptScan).length > 0">
<i class="fa fa-fw fa-file-image-o"></i>
</a>
<span v-else class="text-danger">扫描件待上传</span>
</el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="6" :xs="24">
<span class="border border-danger text-danger rounded px-1">服务截止日期</span> :
{{item.expire_date !== '' ? item.expire_date : noneText}}
</el-col>
<el-col :span="6" :xs="24">
<span class="border border-danger text-danger rounded px-1">下次巡检日期</span> :
{{item.remind_date !== '' ? item.remind_date : noneText}}
</el-col>
<el-col :span="6" :xs="24">
<span class="border border-danger text-danger rounded px-1">SLA</span> :
{{item.sla !== '' ? item.sla : noneText}}
</el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="12" :xs="24">
<span class="border border-danger text-danger rounded px-1">备注</span> :
{{item.description !== '' ? item.description : noneText}}
</el-col>
<el-col :span="12" :xs="24">
<slot name="opearate">
</slot>
</el-col>
</el-row>
</el-col>
</el-row>
</section>
</template>
<script>
export default {
name: 'scheduleItem',
props: {
item: Object
},
data () {
return {
noneText: '(未设置)'
}
},
methods: {
showProject (project) {
this.$emit('update:showProject', project)
},
splitFileName (text) {
var pattern = /\.{1}[a-z]{1,}$/
if (pattern.exec(text) !== null) {
return (text.slice(0, pattern.exec(text).index))
} else {
return text
}
},
getScanUrl (item, key) {
let names = item[key].name.split('/')
let name = names[names.length - 1]
return '/attachment/view?name=' + this.splitFileName(name)
},
setBr (text) {
if (text === '') {
return this.noneText
} else {
return text.replace(/\n/g, '<br />')
}
},
toView (item) {
this.$router.push({
app: 'client',
name: 'viewClient',
params: {
id: item.client_id
}
})
},
toDetailView (item) {
this.$router.push({
app: 'salesOrders',
name: 'salesOrderView',
params: {
id: item.id
}
})
}
},
computed: {
isNullClient () {
return !this.item.client
},
isPublic () {
return !!this.item.is_public
}
},
mounted () {
}
}
</script>
<style scoped lang="scss">
.text-info {
color: #17a2b8 !important;
}
.border-info {
border-color: #17a2b8 !important;
}
.colRed {
color: red;
border: 1px solid red;
}
.colGreen {
color: green;
border: 1px solid green;
}
.colRed, .colGreen, .col {
border-radius: .25rem;
padding: 0 .25rem;
}
.rounded-circle {
border-radius: 50% !important;
}
.user-avatar {
width: 16px;
max-width: 16px;
height: 16px;
max-height: 16px;
}
@include c('schedule-item') {
margin-bottom: 10px;
font-size: 12px;
.border {
border: 1px solid #dee2e6;
}
.border-success {
border-color: #28a745 !important;
}
.border-danger {
border-color: #dc3545;
}
.text-success {
color: #28a745 !important;
}
.text-danger {
color: #E45744;
}
.rounded {
border-radius: .25rem !important;
}
.px-1 {
padding: 0 .25rem;
}
}
@include c('schedule-item:first-child') {
.client-schedule-left {
border-radius: 5px 0 0 0;
}
}
@include c('schedule-row') {
background-color: white;
display: flex;
flex-wrap: wrap;
}
@include c('schedule-left') {
background-color: #FF6A6A;
min-height: 100%;
padding: 10px 15px 6px;
.fa-fw {
width: 1.28571429em;
}
> .el-row {
> .el-col {
margin-bottom: 4px;
}
}
.el-row div:first-child, .el-row div:first-child a, .entity-name, .entity-name a {
color: white;
}
.entity-name .black {
color: #000000;
}
span {
display: inline-block;
padding-left: 3px;
}
span.np {
padding-left: 0;
}
@include e('private') {
display: inline-block;
// border: 1px solid black;
padding-right: 5px;
border-radius: 5px;
width: 40px;
height: 20px;
}
}
@include c('schedule-right') {
height: 100%;
padding: 10px 15px 6px;
> .el-row {
> .el-col {
margin-bottom: 4px;
.el-button {
margin: 0 2px;
padding: 7px;
}
.date-time, .show-picture {
color: #649FD7;
}
.show-picture {
cursor: pointer;
}
}
}
.badge {
border-radius: 2px;
color: #333744;
background: #ffffff;
vertical-align: baseline;
display: inline;
padding: 2px 6px;
text-align: center;
}
span.badge-unread {
&:hover {
border-color: #de321d
}
color: #fff;
background-color: #e54c3a;
border-color: #a32516
}
@include e('item') {
display: flex;
flex-direction: column;
justify-content: space-around;
padding: 5px 0 5px 5px;
flex: 1;
}
@include e('status') {
color: red;
}
@include e('content') {
display: inline-block;
border: 1px solid red;
border-radius: 5px;
height: 20px;
padding: 0 5px 0 5px;
color: red;
}
}
</style>
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
type="primary" type="primary"
size="mini" size="mini"
:disabled="!item.can_update" :disabled="!item.can_update"
@click="editProject(item)"> @click.prevent.stop="editProject(item)">
<i class="fa fa-edit"></i> 编辑 <i class="fa fa-edit"></i> 编辑
</el-button> </el-button>
<el-button class="pull-right" <el-button class="pull-right"
...@@ -78,7 +78,7 @@ ...@@ -78,7 +78,7 @@
</leave-message> </leave-message>
</div> </div>
</div> </div>
<side-popup ref="sidePopup" :title="operationTitle"> <side-popup ref="sidePopup" :title="operationTitle" v-click-outside="popupClose">
<component :is="operationPage" :ref="operationPage" @close="getList => {close(getList)}"></component> <component :is="operationPage" :ref="operationPage" @close="getList => {close(getList)}"></component>
</side-popup> </side-popup>
</section> </section>
...@@ -205,6 +205,10 @@ ...@@ -205,6 +205,10 @@
this.$refs.leaveMessage && this.$refs.leaveMessage &&
this.$refs.leaveMessage.btnClose() this.$refs.leaveMessage.btnClose()
}, },
popupClose () {
this.$refs.sidePopup &&
this.$refs.sidePopup.close()
},
delProject (id) { delProject (id) {
this.$confirm('确认删除吗?', '提示').then(() => { this.$confirm('确认删除吗?', '提示').then(() => {
requestAPI(api.delProject, { requestAPI(api.delProject, {
......
...@@ -55,8 +55,6 @@ ...@@ -55,8 +55,6 @@
} }
}, },
created () { created () {
},
mounted () {
} }
} }
</script> </script>
......
...@@ -185,6 +185,9 @@ ...@@ -185,6 +185,9 @@
if (new Date(val) >= new Date(this.clientTimeRange.to)) { if (new Date(val) >= new Date(this.clientTimeRange.to)) {
this.clientTimeRange.to = val this.clientTimeRange.to = val
} }
if (this.clientTimeRange.to === '') {
this.clientTimeRange.to = val
}
}, },
'clientTimeRange.to' (val) { 'clientTimeRange.to' (val) {
if (new Date(val) <= new Date(this.clientTimeRange.from)) { if (new Date(val) <= new Date(this.clientTimeRange.from)) {
...@@ -234,7 +237,7 @@ ...@@ -234,7 +237,7 @@
} }
</style> </style>
<style> <style>
.form-content-time-top .el-form-item__label { .form-content .el-form-item__label {
font-size: .875rem; font-size: .875rem;
font-weight: normal; font-weight: normal;
padding: 0 2px 0 0; padding: 0 2px 0 0;
......
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
type="primary" type="primary"
size="mini" size="mini"
:disabled="!item.can_update" :disabled="!item.can_update"
@click="editProject(item)"> @click.prevent.stop="editProject(item)">
<i class="fa fa-edit"></i> 编辑 <i class="fa fa-edit"></i> 编辑
</el-button> </el-button>
<el-button class="pull-right" <el-button class="pull-right"
...@@ -70,7 +70,7 @@ ...@@ -70,7 +70,7 @@
</leave-message> </leave-message>
</div> </div>
</div> </div>
<side-popup ref="sidePopup" :title="operationTitle"> <side-popup ref="sidePopup" :title="operationTitle" v-click-outside="popupClose">
<component :is="operationPage" :ref="operationPage" @close="getList => {close(getList)}"></component> <component :is="operationPage" :ref="operationPage" @close="getList => {close(getList)}"></component>
</side-popup> </side-popup>
</section> </section>
...@@ -248,7 +248,8 @@ ...@@ -248,7 +248,8 @@
this.loading = true this.loading = true
requestAPI(api.getProjectClient, { requestAPI(api.getProjectClient, {
data: { data: {
id: this.$route.params.id id: this.$route.params.id,
page: this.pagenation.page
} }
}).then(res => { }).then(res => {
this.result.list = res.list this.result.list = res.list
......
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
利润率: {{item.profit_pct}} 利润率: {{item.profit_pct}}
</el-col> </el-col>
<el-col :span="6" :xs="24"> <el-col :span="6" :xs="24">
销售预测: {{Object.keys(item.projectStatus).length === 0 ? noneText : item.salesForecast.name}} 销售预测: {{Object.keys(item.salesForecast).length === 0 ? noneText : item.salesForecast.name}}
</el-col> </el-col>
<el-col :span="6" :xs="24"> <el-col :span="6" :xs="24">
商机类型: 商机类型:
...@@ -131,8 +131,8 @@ ...@@ -131,8 +131,8 @@
}, },
toView (item) { toView (item) {
let obj = { let obj = {
app: 'project', app: 'client',
name: 'ofClient', name: 'viewClient',
params: { params: {
id: item.client_id id: item.client_id
} }
......
...@@ -197,7 +197,7 @@ ...@@ -197,7 +197,7 @@
} }
</style> </style>
<style> <style>
.form-content-time-top .el-form-item__label { .form-content .el-form-item__label {
font-size: .875rem; font-size: .875rem;
font-weight: normal; font-weight: normal;
padding: 0 2px 0 0; padding: 0 2px 0 0;
......
...@@ -81,8 +81,8 @@ ...@@ -81,8 +81,8 @@
}, },
toView (item) { toView (item) {
this.$router.push({ this.$router.push({
app: 'salesOrders', app: 'client',
name: 'ofClient', name: 'viewClient',
params: { params: {
id: item.client_id id: item.client_id
} }
......
...@@ -8,6 +8,9 @@ import multipleEngineer from '../components/common/multipleEngineer' ...@@ -8,6 +8,9 @@ import multipleEngineer from '../components/common/multipleEngineer'
import singleCheckbox from '../components/common/singleCheckbox' import singleCheckbox from '../components/common/singleCheckbox'
import singleSelect from '../components/common/singleSelect' import singleSelect from '../components/common/singleSelect'
import multipleCheckGroup from '../components/common/multipleCheckGroup' import multipleCheckGroup from '../components/common/multipleCheckGroup'
import singleUpload from '../components/common/singleUpload'
import multipleDateInput from '../components/common/multipleDateInput'
import multipleDatePicker from '../components/common/multipleDatePicker'
export default { export default {
components: { components: {
singleRadio, singleRadio,
...@@ -19,6 +22,9 @@ export default { ...@@ -19,6 +22,9 @@ export default {
multipleEngineer, multipleEngineer,
singleCheckbox, singleCheckbox,
singleSelect, singleSelect,
multipleCheckGroup multipleCheckGroup,
singleUpload,
multipleDateInput,
multipleDatePicker
} }
} }
...@@ -2,6 +2,7 @@ import portal from 'vis-portal' ...@@ -2,6 +2,7 @@ import portal from 'vis-portal'
import ElementRoute from './routes/project' import ElementRoute from './routes/project'
import salesOrder from './routes/salesOrders' import salesOrder from './routes/salesOrders'
import salesContracts from './routes/salesContracts'
let routes = [] let routes = []
let salesRours = [] let salesRours = []
const appName = 'project' const appName = 'project'
...@@ -15,6 +16,9 @@ let RouterInit = () => { ...@@ -15,6 +16,9 @@ let RouterInit = () => {
portal.createApp('salesOrders', {}, app => { portal.createApp('salesOrders', {}, app => {
app.mapRoute(salesRours) app.mapRoute(salesRours)
}) })
portal.createApp('salesContracts', {}, app => {
app.mapRoute(salesContracts)
})
} }
export default RouterInit export default RouterInit
import contractList from '../components/contract/list'
import contractOfClient from '../components/contract/contractOfClient/contractOfClient'
const projectTitle = '金畅逍BMS - '
const routes = [
{
path: '/salesContract',
name: 'contractList',
component: contractList,
meta: {
title: projectTitle + '销售记录'
}
},
{
path: '/ofClient/:id',
name: 'ofClient',
component: contractOfClient,
meta: {
title: projectTitle + '客户信息'
}
}
]
export default routes
This source diff could not be displayed because it is too large. You can view the blob instead.
[
{
"request": {
"uri": "/bankimage/uploadImgToBank"
},
"response": {
"json": {
"code": 2000,
"msg": "\u4e0a\u4f20\u6210\u529f",
"result": {
"id": 2431,
"key": 2431,
"name": "30ccf431-5b04-303a-ad2b-238cf544d0b6.jpeg",
"orig_name": "WechatIMG13175.jpeg",
"path": "/files/protected/a57be577deb434/2019/04/30ccf431-5b04-303a-ad2b-238cf544d0b6.jpeg",
"size": 97461
}
}
}
}
]
[
{
"request": {
"method": "options"
},
"response": {
"headers": {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers": "origin, accept, content-type, x-token",
"Access-Control-Allow-Method": "post, get, options"
}
}
}
]
...@@ -2,61 +2,6 @@ ...@@ -2,61 +2,6 @@
{ {
"include": "options-request.json" "include": "options-request.json"
}, },
{
"request": {
"method": "get"
},
"response": {
"headers": {
"Access-Control-Allow-Origin": "*"
}
},
"include": "element/test.json"
},
{
"request": {
"method": "post"
},
"response": {
"headers": {
"Access-Control-Allow-Origin": "*"
}
},
"include": "element/getUsers.json"
},
{
"request": {
"method": "post"
},
"response": {
"headers": {
"Access-Control-Allow-Origin": "*"
}
},
"include": "element/queryContent.json"
},
{
"request": {
"method": "post"
},
"response": {
"headers": {
"Access-Control-Allow-Origin": "*"
}
},
"include": "element/import.json"
},
{
"request": {
"method": "post"
},
"response": {
"headers": {
"Access-Control-Allow-Origin": "*"
}
},
"include": "element/department.json"
},
{ {
"request": { "request": {
"method": "post" "method": "post"
...@@ -66,6 +11,6 @@ ...@@ -66,6 +11,6 @@
"Access-Control-Allow-Origin": "*" "Access-Control-Allow-Origin": "*"
} }
}, },
"include": "element/status.json" "include": "element/upload.json"
} }
] ]
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