[add] UI 修改

This commit is contained in:
sdaduanbilei-d1581 2025-09-18 11:56:41 +08:00
parent ba4b062cae
commit 7ae0e9c0d3
38 changed files with 0 additions and 5775 deletions

View File

@ -1,125 +0,0 @@
<template>
<div>
<a-button type="primary" size="small" @click="show = true">
<template #icon>
<icon-plus />
</template>
<template #default> 新增客户 </template>
</a-button>
<a-modal
v-model:visible="show"
:mask-closable="false"
@close="this.$refs.form.resetFields()"
@before-ok="submit"
>
<div>
<a-form auto-label-width :model="form" ref="form">
<a-form-item
label="企业/机构名称"
field="name"
:rules="[
{ required: true, message: '请输入企业/机构名称' }
]"
>
<a-input
placeholder="请输入企业/机构名称"
v-model="form.name"
></a-input>
</a-form-item>
<a-form-item
field="cityCode"
label="所属地区"
:rules="[{ required: true, message: '请选择所属地区' }]"
>
<a-cascader
placeholder="请选择所属地区"
:options="options"
allow-search
v-model="form.cityCode"
:field-names="{
label: 'name',
value: 'code'
}"
/>
</a-form-item>
<a-form-item label="详细地址" field="address">
<a-input
placeholder="请输入详细地址"
v-model="form.address"
></a-input>
</a-form-item>
<a-form-item
field="type"
label="客户类型"
:rules="[{ required: true, message: '请选择类型' }]"
>
<a-select placeholder="请选择类型" v-model="form.type">
<a-option label="业主单位" :value="0"></a-option>
<a-option label="实施单位" :value="1"></a-option>
<a-option label="其他" :value="2"></a-option>
</a-select>
</a-form-item>
<a-form-item label="备注" field="remark">
<a-textarea
placeholder="请输入备注"
v-model="form.remark"
></a-textarea>
</a-form-item>
</a-form>
</div>
</a-modal>
</div>
</template>
<script>
export default {
data() {
return {
show: false,
options: [],
userOptions: [],
form: {
name: '',
cityCode: '',
cityName: '',
address: '',
remark: '',
type: 0
}
}
},
mounted() {
this.fetchCity()
},
methods: {
fetchCity() {
this.$api.base.areaTree({code:53}).then(res => {
if (res.code === 200) {
this.options = res.data
}
})
},
submit(done) {
this.$refs.form.validate(errors => {
if (errors === undefined) {
this.$api.customer.submit(this.form).then(res => {
if (res.code === 200) {
this.$notification.success(res.msg)
this.$emit('ok')
done()
} else {
this.$notification.error(res.msg)
done(false)
}
})
} else {
done(false)
}
})
}
}
}
</script>
<style lang="scss" scoped></style>

View File

@ -1,82 +0,0 @@
<template>
<div>
<a-button type="text" size="small" @click="show = true">
新增
</a-button>
<a-modal
v-model:visible="show"
@close="this.$refs.form.resetFields()"
@before-ok="submit"
>
<div>
<a-form auto-label-width :model="form" ref="form">
<a-form-item label="名称" required field="name">
<a-input
v-model="form.name"
placeholder="请输入名称"
></a-input>
</a-form-item>
<a-form-item label="排序" required field="sort">
<a-input-number
v-model="form.sort"
placeholder="请输入排序"
></a-input-number>
</a-form-item>
</a-form>
</div>
</a-modal>
</div>
</template>
<script>
export default {
props: {
pid: {
type: Number,
default: 0
}
},
watch: {
pid: {
handler(val) {
if (val) {
this.form.pid = val
}
},
immediate: true
}
},
data() {
return {
show: false,
form: {
name: '',
pid: 0,
sort: ''
}
}
},
methods: {
submit(done) {
this.$refs.form.validate(errors => {
if (errors === undefined) {
this.$api.base.submit(this.form).then(res => {
if (res.code === 200) {
this.$notification.success(res.msg)
this.$emit('ok')
done()
} else {
done(false)
this.$notification.error(res.msg)
}
})
} else {
done(false)
}
})
}
}
}
</script>
<style lang="scss" scoped></style>

View File

@ -1,93 +0,0 @@
<template>
<div>
<a-button type="primary" size="small" @click="show = true"
>修改权限
</a-button>
<a-modal v-model:visible="show" @ok="submit">
<div>
<div v-for="(item, index) in roleList">
<div
class="padding flex flex-center flex-justify-between row"
@click="changeRole(index)"
>
<div>{{ item.name }}</div>
<icon-check-circle-fill
v-if="item.checked"
style="color: green"
/>
<icon-check-circle v-else />
</div>
</div>
</div>
</a-modal>
</div>
</template>
<script>
export default {
props: {
userId: {
type: String,
default: ''
},
roleId: {
type: String,
default: ''
}
},
watch: {
show: {
handler(val) {
if (val) {
this.fetchRole()
}
}
}
},
data() {
return {
show: false,
roleList: []
}
},
methods: {
changeRole(index) {
this.roleList = this.roleList.map(e => {
e.checked = false
return e
})
this.roleList[index].checked = true
},
fetchRole() {
this.$api.sys.roleList({ appid: 'E191C42B' }).then(res => {
if (res.code === 200) {
this.roleList = res.data
.filter(e => e.code !== 'super_admin')
.map(e => {
e.checked = e.id === this.roleId
return e
})
}
})
},
submit() {
const role = this.roleList.find(e => e.checked)
const data = { id: this.userId, roleId: role.id }
this.$api.user.update(data).then(res => {
if (res.code === 200) {
this.$notification.success(res.msg)
this.$emit('ok')
} else {
this.$notification.error(res.msg)
}
})
}
}
}
</script>
<style lang="scss" scoped>
.row:hover {
background-color: #f0f1f3;
}
</style>

View File

@ -1,229 +0,0 @@
<template>
<div>
<a-button type="text" size="small" @click="show = true"
>{{ info ? '编辑' : '新增' }}
</a-button>
<a-modal
v-model:visible="show"
:mask-closable="false"
width="760px"
@before-ok="submit"
@close="this.$refs.form.resetFields()"
>
<a-form
:model="form"
auto-label-width
ref="form"
:layout="'vertical'"
>
<a-row gutter="16">
<a-col span="12">
<a-form-item
label="工号(登录账号)"
required
field="account"
:disabled="info"
>
<a-input
placeholder="请输入工号(登录账号)"
v-model="form.account"
></a-input>
</a-form-item>
</a-col>
<a-col span="12">
<a-form-item label="登录密码" required field="pwd">
<div class="flex flex-center full-width">
<a-input
placeholder="请输入登录密码"
v-model="form.pwd"
:disabled="info"
></a-input>
<a-button
class="ml-10"
type="primary"
@click="genPwd"
:disabled="info"
>随机密码
</a-button>
</div>
</a-form-item>
</a-col>
</a-row>
<a-row gutter="16">
<a-col span="12">
<a-form-item label="姓名" required field="name">
<a-input
placeholder="请输入姓名"
v-model="form.name"
></a-input>
</a-form-item>
</a-col>
<a-col span="12">
<a-form-item label="性别" required field="sex">
<a-select v-model="form.sex">
<a-option label="男" value="0"></a-option>
<a-option label="女" value="1"></a-option>
</a-select>
</a-form-item>
</a-col>
</a-row>
<a-row gutter="16">
<a-col span="12">
<a-form-item label="联系电话" required field="phone">
<a-input
placeholder="请输入联系电话"
v-model="form.phone"
></a-input>
</a-form-item>
</a-col>
<a-col span="12">
<a-form-item label="所属部门" required field="deptId">
<a-select
placeholder="请选择所属部门"
v-model="form.deptId"
:options="deptOptions"
>
</a-select>
</a-form-item>
</a-col>
</a-row>
<a-row gutter="16">
<a-col span="12">
<a-form-item label="员工岗位" required field="post">
<a-select
placeholder="请选择岗位"
:options="orgPost"
v-model="form.post"
></a-select>
</a-form-item>
</a-col>
<a-col span="12">
<a-form-item label="员工角色" required field="roleId">
<a-select
placeholder="请选择员工角色"
:options="roleOptions"
v-model="form.roleId"
></a-select>
</a-form-item>
</a-col>
</a-row>
</a-form>
</a-modal>
</div>
</template>
<script>
export default {
props: {
info: {
type: Object,
default: null
},
deptId: {
required: true,
type: String,
default: ''
}
},
watch: {
info: {
handler(val) {
if (val) {
this.form = val
}
},
immediate: true
},
show: {
handler(val) {
if (val) {
let dept = JSON.parse(sessionStorage.getItem('dept'))
this.deptOptions = dept.map(e => {
return { label: e.name, value: e.id }
})
this.fetchDict()
}
}
},
deptId: {
handler(val) {
if (val) {
this.form.deptId = val
}
},
immediate: true
}
},
data() {
return {
show: false,
orgPost: [],
roleOptions: [],
deptOptions: [],
form: {
sex: '0',
phone: '',
roleId: '',
account: '',
name: '',
deptId: 0,
pwd: '',
orgId: '',
post: ''
}
}
},
mounted() {
const user = JSON.parse(localStorage.getItem('user'))
this.form.orgId = user.orgId
},
methods: {
fetchDict() {
this.$api.sys.dict({ code: 'org_post' }).then(res => {
if (res.code === 200) {
this.orgPost = res.data
}
})
this.$api.sys.roleList({ appid: 'E191C42B' }).then(res => {
if (res.code === 200) {
this.roleOptions = res.data.map(e => {
return { label: e.name, value: e.id }
})
}
})
},
genPwd() {
let chars =
'0123456789abcdefghijklmnopqrstuvwxyz!@#$%^&*()ABCDEFGHIJKLMNOPQRSTUVWXYZ'
let passwordLength = 6
let password = ''
for (let i = 0; i <= passwordLength; i++) {
let randomNumber = Math.floor(Math.random() * chars.length)
password += chars.substring(randomNumber, randomNumber + 1)
}
this.form.pwd = password
},
submit(done) {
this.$refs.form.validate(errors => {
if (errors === undefined) {
this.$api.base.userSave(this.form).then(res => {
if (res.code === 200) {
this.$notification.success(res.msg)
this.$emit('ok')
done()
} else {
this.$notification.error(res.msg)
done(false)
}
})
} else {
done(false)
}
})
}
}
}
</script>
<style lang="scss" scoped></style>

View File

@ -1,116 +0,0 @@
<template>
<div>
<div class="flex flex-center flex-justify-between mb-10">
<div class="flex flex-center flex-justify-start">
<h2 class="bold">
{{ deptName }}
</h2>
<div class="grey-6 ml-10 bold">
共有员工{{ this.list.length }}
</div>
</div>
<add-user :dept-id="deptId" @ok="fetchList" />
</div>
<a-table
:columns="columns"
:data="list"
:pagination="page"
@page-change="pageChange"
>
<template #sex="{ record }">
<a-tag color="blue">
{{ record.sex === '0' ? '男' : '女' }}
</a-tag>
</template>
<template #status="{ record }">
<a-tag color="red" v-if="record.status === 0"> 未激活</a-tag>
<a-tag color="green" v-else-if="record.status === 1">
已激活
</a-tag>
<a-tag color="grey" v-else> 停用/离职</a-tag>
</template>
<template #menu="{ record }">
<div>
<view-user :userId="record.id" @ok="refresh" />
</div>
</template>
</a-table>
</div>
</template>
<script>
import addUser from '@/views/base/components/edit.vue-user.vue'
import viewUser from '@/views/base/components/view-user.vue'
export default {
components: {
addUser,
viewUser
},
props: {
deptName: {
required: true,
type: String,
default: ''
},
deptId: {
required: true,
type: String,
default: ''
}
},
watch: {
deptId: {
handler(val) {
this.fetchList()
},
immediate: true
}
},
data() {
return {
page: { page: 0, size: 10 },
list: [],
columns: [
{ title: '账号', dataIndex: 'account' },
{ title: '姓名', dataIndex: 'name' },
{ title: '性别', slotName: 'sex' },
{ title: '状态', slotName: 'status' },
{ title: '添加时间', dataIndex: 'createdAt' },
{ title: '操作', slotName: 'menu' }
]
}
},
methods: {
refresh() {
this.fetchAll()
},
fetchList() {
this.$api.base
.userList({ deptId: this.deptId})
.then(res => {
if (res.code === 200) {
this.list = res.data
this.page.total = res.data.length
}
})
},
fetchAll() {
const data = { deptId: this.deptId, ...this.page }
this.$api.base.userAll(data).then(res => {
if (res.code === 200) {
this.list = res.data.records
this.page.total = res.data.total
}
})
},
pageChange(page) {
this.page.page = page - 1
this.refresh()
}
}
}
</script>
<style lang="scss" scoped></style>

View File

@ -1,220 +0,0 @@
<template>
<div>
<a-button type="text" size="small" @click="show = true">查看</a-button>
<a-drawer v-model:visible="show" width="960px">
<div v-if="user">
<div class="flex flex-center flex-justify-start">
<a-avatar :size="72">
<a-image
alt="avatar"
v-if="user.avatar"
:src="user.avatar"
style="border-radius: 50%"
/>
</a-avatar>
<div class="ml-20">
<div class="flex flex-center flex-justify-between">
<h2>{{ user.name }}</h2>
</div>
<div class="flex flex-justify-start flex-center">
账号状态
<div>
<a-tag color="red" v-if="user.status === 0"
>未激活
</a-tag>
<a-tag
color="green"
v-else-if="user.status === 1"
>正常
</a-tag>
<a-tag color="grey" v-else>停用/离职</a-tag>
</div>
</div>
<div>创建时间{{ user.createTime }}</div>
</div>
</div>
<a-divider />
<div>
<div class="flex flex-center flex-justify-between">
<h2 class="padding-top padding-bottom">基础信息</h2>
<edit-user
:dept-id="user.deptId"
:info="user"
@ok="fetchInfo"
></edit-user>
</div>
<a-descriptions :data="data" bordered />
</div>
<div class="padding-top padding-bottom">
<h2 class="padding-top padding-bottom">修改</h2>
<div class="flex flex-center flex-justify-start">
<a-popconfirm
content="确定重置密码为 000000 "
@ok="restPwd"
>
<a-button type="primary" size="small"
>重置密码
</a-button>
</a-popconfirm>
<a-popconfirm
:content="
`确定` + this.user.status === 1
? '停用'
: '启用' + `当前账号?`
"
@ok="changeStatus"
>
<a-button
class="ml-20"
v-if="user.status === 0"
type="primary"
disabled
size="small"
>
账号未激活
</a-button>
<a-button
v-else
class="ml-20"
type="primary"
size="small"
>
{{
this.user.status === 1
? '停用账号'
: '启用账号'
}}
</a-button>
</a-popconfirm>
<div class="ml-20">
<edit-role
:userId="user.id"
:roleId="user.roleId"
@ok="fetchInfo"
/>
</div>
</div>
</div>
</div>
</a-drawer>
</div>
</template>
<script>
import editUser from '@/views/base/components/edit.vue-user.vue'
import editRole from '@/views/base/components/edit.vue-role.vue'
export default {
components: {
editUser,
editRole
},
props: {
userId: {
type: String,
default: ''
}
},
watch: {
show: {
handler(val) {
if (val) {
this.fetchInfo()
}
}
}
},
data() {
return {
show: false,
user: null,
data: [
{
label: '姓名',
prop: 'name'
},
{
label: '性别',
prop: 'sex'
},
{
label: '电话',
prop: 'phone'
},
{
label: '职务',
prop: 'postName'
},
{
label: '角色',
prop: 'roleName'
}
]
}
},
methods: {
fetchInfo() {
this.$api.user.info({ id: this.userId }).then(res => {
if (res.code === 200) {
this.user = res.data
this.fetchData(res.data)
} else {
this.$notification.error(res.msg)
}
})
},
fetchData(info) {
//
this.$api.sys.dict({ code: 'org_post' }).then(res => {
if (res.code === 200) {
var tmp = res.data.find(e => e.value === info.post)
if (tmp) {
info.postName = tmp.label
}
this.$api.sys.roleList({ appid: 'E191C42B' }).then(res => {
var tmp = res.data.find(e => e.id === info.roleId)
if (tmp) {
info.roleName = tmp.name
}
info.sex = info.sex === '0' ? '男' : '女'
this.data = this.data.map(e => {
const item = {}
item.label = e.label
item.value = info[e.prop]
item.prop = e.prop
return item
})
})
}
})
},
restPwd() {
const data = {id: this.user.id, pwd: '000000'}
this.$api.user.update(data).then(res => {
if (res.code === 200) {
this.$notification.success(res.msg)
} else {
this.$notification.error(res.msg)
}
})
},
changeStatus() {
const data = {
id: this.user.id,
status: this.user.status === 1 ? 2 : 1
}
this.$api.user.update(data).then(res => {
if (res.code === 200) {
this.$notification.success(res.msg)
this.user.status = data.status
this.$emit('ok')
} else {
this.$notification.error(res.msg)
}
})
}
}
}
</script>
<style lang="scss" scoped></style>

View File

@ -1,104 +0,0 @@
<template>
<div>
<a-table :columns="columns" :data="list">
<template #sex="{ record }">
<a-tag :color="record.sex === '0' ? 'blue' : 'red'"
>{{ record.sex === '0' ? '男' : '女' }}
</a-tag>
</template>
<template #isPolicy="{ record }">
<div>
<a-tag :color="record.isPolicy === false ? 'red' : 'green'"
>{{ record.isPolicy === false ? '否' : '是' }}
</a-tag>
</div>
</template>
<template #menu="{ record }">
<div>
<edit-contacts
:customer-id="customerId"
:info="record"
@ok="fetchList"
></edit-contacts>
</div>
</template>
</a-table>
</div>
</template>
<script>
import editContacts from '@/views/base/customer/components/edit.vue-contacts.vue'
export default {
components: {
editContacts
},
props: {
customerId: {
required: true,
type: String,
default: ''
}
},
watch: {
customerId: {
handler(val) {
if (val) {
this.fetchList()
}
},
immediate: true
}
},
data() {
return {
page: { page: 0, size: 10, total: 0 },
list: [],
columns: [
{
title: '姓名',
dataIndex: 'name'
},
{
title: '性别',
slotName: 'sex'
},
{
title: '手机号码',
dataIndex: 'phone'
},
{
title: '职务',
dataIndex: 'post'
},
{
title: '关键决策人',
slotName: 'isPolicy'
},
{
title: '备注',
dataIndex: 'remark'
},
{
title: '操作',
slotName: 'menu'
}
]
}
},
methods: {
fetchList() {
const data = { customerId: this.customerId, ...this.page }
this.$api.contacts.page(data).then(res => {
if (res.code === 200) {
this.list = res.data.records
}
})
}
}
}
</script>
<style lang="scss" scoped></style>

View File

@ -1,164 +0,0 @@
<template>
<div>
<a-button type="text" size="small" @click="show = true">查看</a-button>
<a-drawer v-model:visible="show" width="80%" :header="false">
<div v-if="info">
<div class="flex flex-center flex-justify-start">
<h1>{{ info.name }}</h1>
<a-tag size="large" color="red" class="ml-20"
>业务员{{ info.user.name }}</a-tag>
</div>
<div class="flex flex-center flex-justify-start">
<a-tag color="blue" size="large">
{{ info.region.province_name }}{{ info.region.city_name }}{{ info.region.name }}
</a-tag>
<div class="ml-10">
<a-input
v-model="info.address"
size="small"
style="min-width: 680px"
placeholder="详细地址"
:disabled="!editAddr"
>
<template #suffix>
<a-button type="text" size="small" @click="save"
>{{ editAddr ? '保存' : '编辑' }}
</a-button>
</template>
</a-input>
</div>
</div>
<a-divider />
<div class="flex flex-center flex-justify-start">
<edit-contacts
:customer-id="info.id"
@ok="this.$refs.contacts.fetchList()"
/>
<a-button size="small" class="ml-10">
<template #icon>
<icon-code-square />
</template>
创建项目
</a-button>
</div>
<div class="mt-20">
<a-tabs @change="tabChange">
<a-tab-pane
v-for="item in tabs"
:key="item.value"
:title="item.title"
>
</a-tab-pane>
</a-tabs>
<div class="padding" v-if="tabIndex === 0">
<contacts :customer-id="id" ref="contacts" />
</div>
<div
v-else
class="flex flex-center flex-col grey-6"
style="margin-top: 96px"
>
<img
style="width: 100px"
src="https://res.wutongshucloud.com/res/2024/12/09/202412091020938.svg"
/>
<div>正在开发中</div>
</div>
</div>
</div>
</a-drawer>
</div>
</template>
<script>
import Contacts from '@/views/base/customer/components/contacts.vue'
import editContacts from '@/views/base/customer/components/edit.vue-contacts.vue'
export default {
components: { Contacts, editContacts },
props: {
id: {
type: String,
default: ''
}
},
watch: {
show: {
handler(val) {
if (val) {
this.fetchInfo()
}
}
}
},
data() {
return {
info: null,
city: null,
show: false,
editAddr: false,
tabIndex: 0,
tabs: [
{
title: '联系人',
value: 0
},
{
title: '相关项目',
value: 1
},
{
title: '详细信息',
value: 2
}
]
}
},
methods: {
tabChange(res) {
this.tabIndex = res
},
fetchInfo() {
this.$api.customer.info({ id: this.id }).then(res => {
if (res.code === 200) {
this.info = res.data
}
})
},
fetchCity(code) {
this.$api.base.areaDetail({ code: code }).then(res => {
if (res.code === 200) {
this.city = res.data
}
})
},
save() {
if (this.editAddr === false) {
this.editAddr = true
} else {
if (this.info.address) {
const data = {
id: this.info.id,
address: this.info.address
}
this.$api.customer.submit(data).then(res => {
if (res.code === 200) {
this.$notification.success(res.msg)
this.editAddr = false
} else {
this.$notification.error(res.msg)
}
})
}
}
}
}
}
</script>
<style lang="scss" scoped>
:deep(.arco-input-wrapper .arco-input[disabled]) {
--color-text-4: #343434;
}
</style>

View File

@ -1,154 +0,0 @@
<template>
<div>
<a-button
v-if="info === null"
size="small"
@click="show = true"
type="primary"
>
<template #icon>
<icon-idcard />
</template>
创建联系人
</a-button>
<a-button v-else size="small" type="text" @click="show = true"
>更新
</a-button>
<a-modal
v-model:visible="show"
@close="this.$refs.form.resetFields()"
@before-ok="submit"
>
<a-form :model="form" ref="form" auto-label-width>
<a-form-item
label="姓名"
field="name"
:rules="[{ required: true, message: '请输入姓名' }]"
>
<a-input
placeholder="请输入姓名"
v-model="form.name"
></a-input>
</a-form-item>
<a-form-item
label="手机"
field="phone"
:rules="[
{ required: true, message: '请输入手机号码' },
{ length: 11, message: '请输入手机号码' }
]"
>
<a-input
placeholder="请输入手机号码"
v-model="form.phone"
></a-input>
</a-form-item>
<a-form-item
label="职务"
field="post"
:rules="[{ required: true, message: '请输入职务' }]"
>
<a-input
placeholder="请输入职务"
v-model="form.post"
></a-input>
</a-form-item>
<a-form-item
label="性别"
field="sex"
:rules="[{ required: true, message: '请选择性别' }]"
>
<a-select placeholder="请选择性别" v-model="form.sex">
<a-option label="男" value="0"></a-option>
<a-option label="女" value="1"></a-option>
</a-select>
</a-form-item>
<a-form-item
label="是否关键决策人"
field="isPolicy"
:rules="[
{ required: true, message: '请选择是否关键决策人' }
]"
>
<a-select
placeolder="请选择"
v-model="form.isPolicy"
placeholder="请选择是否关键决策人"
>
<a-option label="否" :value="false"></a-option>
<a-option label="是" :value="true"></a-option>
</a-select>
</a-form-item>
<a-form-item label="备注" field="remark">
<a-textarea
v-model="form.remark"
placeholder="请输入备注,例如:爱好"
></a-textarea>
</a-form-item>
</a-form>
</a-modal>
</div>
</template>
<script>
export default {
props: {
customerId: {
required: true,
type: String,
default: ''
},
info: {
type: Object,
default: null
}
},
watch: {
info: {
handler(val) {
if (val) {
this.form = { ...val }
}
},
immediate: true
}
},
data() {
return {
show: false,
form: {
name: '',
phone: '',
post: '',
sex: '0',
isPolicy: false,
remark: '',
customerId: ''
}
}
},
methods: {
submit(done) {
this.$refs.form.validate(errors => {
if (errors === undefined) {
this.form.customerId = this.customerId
this.$api.contacts.submit(this.form).then(res => {
if (res.code === 200) {
this.$notification.success(res.msg)
this.$emit('ok')
done()
} else {
this.$notification.error(res.msg)
done(false)
}
})
} else {
done(false)
}
})
}
}
}
</script>
<style lang="scss" scoped></style>

View File

@ -1,105 +0,0 @@
<template>
<div>
<navbar title="客户管理" />
<div class="container">
<div class="flex flex-center flex-justify-start">
<add-org @ok="fetchList" />
</div>
<a-table
class="mt-20"
:columns="columns"
:data="list"
:pagination="page"
@pageChange="pageChange"
>
<template #region="{ record }">
<div>
{{ record.region.province_name }}{{ record.region.city_name }}{{ record.region.name }}
</div>
</template>
<template #menu="{ record }">
<div>
<customer-more :id="record.id" />
</div>
</template>
</a-table>
</div>
</div>
</template>
<script>
import navbar from '@/components/navbar/index.vue'
import addOrg from '@/views/base/components/add-org.vue'
import customerMore from '@/views/base/customer/components/customer-more.vue'
export default {
components: {
navbar,
addOrg,
customerMore
},
data() {
return {
page: {
page: 0,
size: 10,
total: 10
},
list: [],
columns: [
{
title: '单位名称',
dataIndex: 'name',
width:200
},
{
title: '类型',
dataIndex: 'typeName',
width:120
},
{
title: '地区',
slotName: 'region',
width:280
},
{
title: '详细地址',
dataIndex: 'address'
},
{
title: '操作',
slotName: 'menu',
width:200
}
]
}
},
mounted() {
this.fetchList()
},
methods: {
pageChange(page){
this.page.page = page
this.fetchList()
},
fetchList() {
this.$api.customer.page(this.page).then(res => {
if (res.code === 200) {
this.list = res.data.records.map(e => {
e.typeName = '业主单位'
if (e.type === 1) {
e.typeName = '实施单位'
} else if (e.type === 2) {
e.typeName = '其他'
}
return e
})
this.page.total = res.data.total
}
})
}
}
}
</script>
<style lang="scss" scoped></style>

View File

@ -1,100 +0,0 @@
<template>
<div>
<navbar title="部门与员工管理" />
<div class="flex flex-center flex-align-start">
<div class="container mr-10" style="flex: 1">
<div
class="flex flex-center flex-justify-between pointer"
v-if="dept"
@click="subDept = null"
>
<h2>
{{ dept.name }}
</h2>
<edit-dept :pid="dept.id" @ok="fetchList" />
</div>
<a-divider />
<div>
<a-empty v-if="list.length === 0"></a-empty>
<div
v-for="item in list"
:key="item.id"
@click="checkDept(item)"
>
<div
class="flex flex-center flex-justify-start padding row pointer"
>
{{ item.name }}
</div>
</div>
</div>
</div>
<div class="container" style="flex: 3" v-if="dept">
<user
:dept-name="subDept ? subDept.name : dept.name"
:dept-id="subDept ? subDept.id : ''"
/>
</div>
</div>
</div>
</template>
<script>
import navbar from '@/components/navbar/index.vue'
import editDept from '@/views/base/components/edit.vue-dept.vue'
import user from './components/user.vue'
export default {
components: {
navbar,
editDept,
user
},
data() {
return {
dept: "",
subDept: null,
list: []
}
},
mounted() {
this.fetchDeptInfo()
},
methods: {
fetchDeptInfo() {
const user = JSON.parse(localStorage.getItem('user'))
this.$api.base.info({ orgId: user.orgId }).then(res => {
if (res.code === 200) {
this.dept = res.data
this.fetchList()
}
})
},
fetchList() {
this.$api.base.list({ pid: this.dept.id }).then(res => {
if (res.code === 200) {
this.list = res.data
//
const tmps = [...this.list]
tmps.push(this.dept)
sessionStorage.setItem('dept', JSON.stringify(tmps))
}
})
},
checkDept(item) {
this.subDept = item
}
}
}
</script>
<style lang="scss" scoped>
.row {
border-bottom: rgba(0, 0, 0, 0.05) solid 1px;
}
.row:hover {
background-color: #f0f1f3;
}
</style>

View File

@ -1,140 +0,0 @@
<template>
<div>
<a-button
class="mt-20"
type="primary"
size="small"
@click="show = true"
>
<template #icon>
<icon-edit />
</template>
<template #default>创建回款单</template>
</a-button>
<a-modal
v-model:visible="show"
@close="this.$refs.form.resetFields()"
@before-ok="submit"
>
<a-form auto-label-width :model="form" ref="form">
<a-form-item label="回款编号" field="number" required>
<a-input
placeholder="回款编号"
disabled
v-model="form.number"
></a-input>
</a-form-item>
<a-form-item
label="回款金额"
:rules="[{ required: true, message: '请输入回款金额' }]"
field="amount"
>
<a-input-number
v-model="form.amount"
placeholder="请输入回款金额"
></a-input-number>
</a-form-item>
<a-form-item
label="回款日期"
field="payDate"
:rules="[{ required: true, message: '请选择回款日期' }]"
>
<a-date-picker
v-model="form.payDate"
class="full-width"
placeholder="请选择回款日期"
></a-date-picker>
</a-form-item>
<a-form-item label="回款备注">
<a-textarea
v-model="form.remark"
class="full-width"
:auto-size="{ minRows: 5 }"
placeholder="请输入回款备注"
></a-textarea>
</a-form-item>
</a-form>
</a-modal>
</div>
</template>
<script>
export default {
props: {
info: {
required: true,
type: Object,
default: null
}
},
watch: {
show: {
handler(val) {
if (val) {
this.form.number = this.createordernum()
}
}
}
},
data() {
return {
show: false,
form: {
number: '',
amount: '',
payDate: '',
remark: ''
}
}
},
methods: {
setTimeDateFmt(s) {
//
return s < 10 ? '0' + s : s
},
createordernum() {
const now = new Date()
let month = now.getMonth() + 1
let day = now.getDate()
let hour = now.getHours()
let minutes = now.getMinutes()
let seconds = now.getSeconds()
month = this.setTimeDateFmt(month)
day = this.setTimeDateFmt(day)
hour = this.setTimeDateFmt(hour)
minutes = this.setTimeDateFmt(minutes)
seconds = this.setTimeDateFmt(seconds)
let orderCode =
now.getFullYear().toString() +
month.toString() +
day +
hour +
minutes +
seconds +
Math.round(Math.random() * 1000000).toString()
return orderCode
//+
},
submit(done) {
this.$refs.form.validate(errors => {
if (errors === undefined) {
this.form.contractId = this.info.id
this.$api.contractPay.submit(this.form).then(res => {
if (res.code === 200) {
this.$notification.success(res.msg)
this.$emit('ok')
done()
} else {
this.$notification.error(res.msg)
}
})
} else {
done(false)
}
})
}
}
}
</script>
<style lang="scss" scoped></style>

View File

@ -1,137 +0,0 @@
<template>
<div>
<a-collapse :default-active-key="['1']" accordion>
<a-collapse-item header="基础信息" key="1">
<template #extra>
<edit-contract :info="form" @ok="fetchData" />
</template>
<div v-if="data">
<a-descriptions
:data="data"
bordered
:column="{ xs: 1, md: 3, lg: 4 }"
>>
<a-descriptions-item
v-for="item of data"
:label="item.label"
:key="item.id"
>
<div>{{ item.value }}</div>
</a-descriptions-item>
</a-descriptions>
</div>
</a-collapse-item>
<a-collapse-item header="关联项目" key="2">
<template #extra>
<project-picker :contract-id="info.id" @ok="success" />
</template>
<div>
<a-list :bordered="false" size="small">
<a-list-item v-for="item in projects" :key="item.id">
<div
class="flex flex-center flex-justify-between"
v-if="item"
>
<div>{{ item.name }}</div>
<div>
<more-info :info="item" />
</div>
</div>
</a-list-item>
</a-list>
</div>
</a-collapse-item>
</a-collapse>
</div>
</template>
<script>
import editContract from '@/views/contract/components/edit.vue-contract.vue'
import projectPicker from '@/views/contract/components/project-picker.vue'
import moreInfo from '@/views/project/index/components/more-info.vue'
export default {
components: {
editContract,
projectPicker,
moreInfo
},
props: {
info: {
type: Object,
default: null
}
},
watch: {
info: {
handler(val) {
if (val) {
this.form = val
this.projects = val.projects
}
},
immediate: true
},
form: {
handler(val) {
this.fetchData(val)
},
immediate: true
}
},
data() {
return {
form: null,
projects: [],
data: [
{
label: '合同开始日期',
prop: 'startDate'
},
{
label: '合同结束日期',
prop: 'endDate'
},
{
label: '客户签约人',
prop: 'customerContact'
},
{
label: '公司签约人',
prop: 'signatory'
},
{
label: '合同备注',
prop: 'remark'
}
]
}
},
methods: {
success(projects) {
this.projects = projects
},
fetchData(val) {
console.log('base-ok')
this.data = this.data.map(e => {
if (e.prop === 'customerContact') {
e.value = val.customerContact.name
} else if (e.prop === 'signatory') {
e.value = val.signatory ? val.signatory.name : ''
} else {
e.value = val[e.prop]
}
return e
})
this.form = val
this.$emit('ok', val)
}
}
}
</script>
<style lang="scss" scoped>
:deep(.arco-collapse-item-content) {
background-color: white;
}
</style>

View File

@ -1,297 +0,0 @@
<template>
<div>
<a-button type="primary" @click.stop="show = true"
>{{ info ? '编辑' : '新增合同' }}
</a-button>
<a-modal
v-model:visible="show"
width="960px"
title="新增合同"
title-align="start"
@close="reset"
@before-ok="submit"
>
<a-form auto-label-width :model="form" ref="form">
<a-row :gutter="16">
<a-col :span="12">
<a-form-item
label="合同编号"
field="number"
:rules="[
{ required: true, message: '请输入合同编号' }
]"
>
<a-input
placeholder="请输入合同编号"
v-model="form.number"
></a-input>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item
field="person"
label="负责人"
:rules="[
{ required: true, message: '请选择合同负责人' }
]"
>
<a-select
:options="userOptions"
allow-search
@search="handleSearch"
@focusin="handleFocus"
placeholder="请选择合同负责人"
v-model="form.person"
></a-select>
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="16">
<a-col :span="12">
<a-form-item
label="合同名称"
field="name"
:rules="[
{ required: true, message: '请输入合同名称' }
]"
>
<a-input
placeholder="请输入合同名称"
v-model="form.name"
></a-input>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item
label="合同客户"
field="customerId"
:rules="[
{ required: true, message: '请选择合同客户' }
]"
>
<a-select
allow-search
:options="customerOptions"
@search="handleCustomer"
v-model="form.customerId"
placeholder="请选择合同客户"
></a-select>
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="16">
<a-col :span="12">
<a-form-item
label="合同金额"
field="amount"
:rules="[
{ required: true, message: '请输入合同金额' }
]"
>
<a-input-number
v-model="form.amount"
placeholder="请输入合同金额"
></a-input-number>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="签订时间" field="signDate">
<a-date-picker
v-model="form.signDate"
class="full-width"
placeholder="请选择签订时间"
></a-date-picker>
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="16">
<a-col :span="12">
<a-form-item label="合同开始日期" field="startDate">
<a-date-picker
class="full-width"
v-model="form.startDate"
placeholder="请选择合同开始日期"
></a-date-picker>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="合同结束日期" field="endDate">
<a-date-picker
v-model="form.endDate"
class="full-width"
placeholder="请选择合同结束日期"
></a-date-picker>
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="16">
<a-col :span="12">
<a-form-item
label="客户签约人"
field="customerContactId"
>
<a-select
allow-search
:options="customerContactsOptions"
@search="handleContacts"
v-model="form.customerContactId"
placeholder="请选择客户签约人"
></a-select>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="公司签约人" field="signatory">
<a-select
v-model="form.signatory"
allow-search
:options="signOptions"
@search="handleSign"
placeholder="请选择公司签约人"
></a-select>
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="16">
<a-col :span="24">
<a-form-item label="合同备注" field="remark">
<a-textarea
v-model="form.remark"
:auto-size="{ minRows: 5 }"
placeholder="请输入合同备注"
></a-textarea>
</a-form-item>
</a-col>
</a-row>
</a-form>
</a-modal>
</div>
</template>
<script>
export default {
props: {
info: {
type: Object,
default: null
}
},
watch: {
show: {
handler(val) {
if (val && this.info) {
this.form = { ...this.info }
this.handleSearch(this.form.person.name)
this.form.person = this.form.person.id
this.handleCustomer(this.form.customer.name)
this.form.customerId = this.form.customer.id
if (this.form.signatory) {
this.handleSign(this.form.signatory.name)
this.form.signatory = this.form.signatory.id
}
if (this.form.customerContact) {
this.handleContacts(this.form.customerContact.name)
this.form.customerContactId =
this.form.customerContact.id
}
}
}
}
},
data() {
return {
show: false,
form: {
number: '',
person: '',
name: '',
customerId: '',
amount: '',
signDate: '',
startDate: '',
endDate: '',
customerContactId: '',
signatory: '',
remark: ''
},
userOptions: [],
signOptions: [],
customerOptions: [],
customerContactsOptions: []
}
},
methods: {
//
handleSearch(value) {
this.$api.user.list({ name: value }).then(res => {
if (res.code === 200) {
this.userOptions = res.data.map(e => {
return { label: e.name, value: e.id }
})
}
})
},
handleSign(value) {
this.$api.user.list({ name: value }).then(res => {
if (res.code === 200) {
this.signOptions = res.data.map(e => {
return { label: e.name, value: e.id }
})
}
})
},
handleContacts(value) {
this.$api.contacts
.list({ name: value, customerId: this.form.customerId })
.then(res => {
if (res.code === 200) {
this.customerContactsOptions = res.data.map(item => {
return { label: item.name, value: item.id }
})
}
})
},
handleCustomer(value) {
this.$api.customer.all({ name: value }).then(res => {
if (res.code === 200) {
this.customerOptions = res.data.map(e => {
return { label: e.name, value: e.id }
})
}
})
},
handleFocus() {
this.handleSearch('')
},
reset() {
if (!this.form.id) {
this.$refs.form.resetFields()
}
},
submit(done) {
this.$refs.form.validate(errors => {
if (errors === undefined) {
this.$api.contract.submit(this.form).then(res => {
if (res.code === 200) {
this.$notification.success(res.msg)
this.$emit('ok', res.data)
done()
} else {
this.$notification.error(res.msg)
done(false)
}
})
} else {
done(false)
}
})
}
}
}
</script>
<style lang="scss" scoped></style>

View File

@ -1,129 +0,0 @@
<template>
<div>
<div class="mb-20 flex flex-center flex-justify-between">
<div>
<a-input
style="width: 360px"
placeholder="请输入文件名称"
allow-clear
v-model="name"
@clear="fetchList"
></a-input>
<a-button type="primary" class="ml-20" @click="fetchList"
>搜索</a-button
>
</div>
<upload @ok="uplodSucc" />
</div>
<a-table
:columns="columns"
:data="list"
:pagination="page"
@page-change="pageChange"
>
<template #user="{ record }">
<div>
{{ record.user.name }}
</div>
</template>
<template #menu="{ record }">
<preview :file-id="record.fileId" />
</template>
</a-table>
</div>
</template>
<script>
import upload from '@/components/upload/index.vue'
import preview from '@/components/preview/index.vue'
export default {
props: {
info: {
required: true,
type: Object,
default: null
}
},
components: {
upload,
preview
},
watch: {
info: {
handler(val) {
if (val) {
this.fetchList()
}
},
immediate: true
}
},
data() {
return {
name: '',
page: {
page: 0,
size: 10,
total: 0
},
columns: [
{
title: '文件名称',
dataIndex: 'name'
},
{
title: '上传人',
slotName: 'user'
},
{
title: '上传时间',
dataIndex: 'createTime'
},
{
title: '操作',
slotName: 'menu'
}
],
list: []
}
},
methods: {
pageChange(page) {
this.page.page = page - 1
this.fetchList()
},
fetchList() {
const data = {
contractId: this.info.id,
name: this.name,
...this.page
}
this.$api.contractFile.page(data).then(res => {
if (res.code === 200) {
this.list = res.data.records
this.page.total = res.data.total
}
})
},
uplodSucc(res) {
const data = {
fileId: res.id,
name: res.fileName,
contractId: this.info.id
}
this.$api.contractFile.submit(data).then(res => {
if (res.code === 200) {
this.fetchList()
this.$notification.success(res.msg)
} else {
this.$notification.error(res.msg)
}
})
}
}
}
</script>
<style lang="scss" scoped></style>

View File

@ -1,178 +0,0 @@
<template>
<div>
<a-button type="text" @click="show = true">更多</a-button>
<a-drawer
width="80%"
v-model:visible="show"
:header="false"
:footer="false"
>
<a-card class="mt-20">
<a-descriptions
v-if="info"
:data="data"
:title="info.name"
bordered
/>
<a-empty v-else description="暂无合同"> </a-empty>
</a-card>
<div>
<a-tabs
class="mt-10"
@change="tabChange"
:active-key="tabIndex"
>
<a-tab-pane title="合同附件" key="0"></a-tab-pane>
<a-tab-pane title="合同回款" key="1"></a-tab-pane>
</a-tabs>
</div>
<div v-if="tabIndex === 0 && info">
<attach
:type="2"
:query-id="info.id"
:project-id="info.projectId"
/>
</div>
</a-drawer>
</div>
</template>
<script>
import xbase from '@/views/contract/components/base.vue'
import files from '@/views/contract/components/files.vue'
import payLog from '@/views/contract/components/pay-log.vue'
import attach from '@/views/project/components/attach/index.vue'
export default {
components: {
attach,
xbase,
files,
payLog
},
props: {
id: {
required: true,
type: String,
default: ''
}
},
watch: {
show: {
handler(val) {
if (val) {
this.form = this.info
this.fetchInfo()
} else {
this.tabIndex = 0
}
}
}
},
data() {
return {
tabIndex: 0,
show: false,
form: null,
info: null,
data: [
{
label: '合同编号',
prop: 'number'
},
{
label: '合同类型',
prop: 'number'
},
{
label: '合同金额 单位:元',
prop: 'amount'
},
{
label: '签订时间',
prop: 'signDate'
},
{
label: '合同开始日期',
prop: 'startDate'
},
{
label: '合同结束日期',
prop: 'endDate'
},
{
label: '对方单位名称',
prop: 'customer'
},
{
label: '对方单位联系人',
prop: 'contact'
},
{
label: '我方单位名称',
prop: 'org'
},
{
label: '我方负责联系人',
prop: 'person'
},
{
label: '备注',
prop: 'remark'
}
]
}
},
methods: {
changeStatus(res) {
this.form.status = res
const data = { id: this.form.id, status: this.form.status.value }
this.$api.contract.submit(data).then(res => {
if (res.code === 200) {
this.$notification.success(res.msg)
} else {
this.$notification.error(res.msg)
}
})
},
tabChange(index) {
this.tabIndex = Number.parseInt(index)
},
update(val) {
this.form = val
this.init()
},
fetchInfo() {
this.$api.contract.info({ id: this.id }).then(res => {
if (res.code === 200) {
this.info = res.data
this.fetchData()
}
})
},
fetchData() {
this.data = this.data.map(e => {
const item = e
item.value = this.info[e.prop]
if (e.prop === "person"){
item.value = this.info.personInfo.name
}
if (e.prop === "org"){
item.value = this.info.org.label
}
if (e.prop === "customer"){
item.value = this.info.customer.name
}
if (e.prop === "contact"){
item.value = this.info.contact.name
}
return item
})
},
}
}
</script>
<style lang="scss" scoped></style>

View File

@ -1,199 +0,0 @@
<template>
<div>
<a-button type="text" size="small" @click="show = true">更多</a-button>
<a-drawer v-model:visible="show" width="80%" :header="false">
<div v-if="form">
<div>
<div>
<div>
{{ form.user.name }} 创建于 {{ form.createTime }}
</div>
</div>
<div class="flex flex-center flex-justify-start">
<div class="font-24 bold">{{ form.number }}</div>
<div class="ml-20">
<a-dropdown @select="changeStatus">
<a-button
type="primary"
size="small"
:style="
`background-color:` + form.status.remark
"
>{{ form.status.label }}
</a-button>
<template #content>
<a-doption
v-for="item in dict"
:key="item.id"
:value="item"
>{{ item.label }}
</a-doption>
</template>
</a-dropdown>
</div>
</div>
</div>
<a-descriptions
:data="data"
class="mt-20"
bordered
:column="{ xs: 1, md: 3, lg: 4 }"
>>
<a-descriptions-item
v-for="item of data"
:label="item.label"
:key="item.id"
>
<div>{{ item.value }}</div>
</a-descriptions-item>
</a-descriptions>
</div>
<div class="font-18 bold mt-20">附件</div>
<a-divider />
<div class="mb-20 mt-20">
<upload @ok="success" />
</div>
<a-table :columns="columns" :data="list">
<template #user="{ record }">
<div>
{{ record.user.name }}
</div>
</template>
<template #menu="{ record }">
<div>
<preview :file-id="record.fileId" />
</div>
</template>
</a-table>
</a-drawer>
</div>
</template>
<script>
import upload from '@/components/upload/index.vue'
import preview from '@/components/preview/index.vue'
export default {
components: {
upload,
preview
},
props: {
info: {
required: true,
type: Object,
default: null
}
},
watch: {
show: {
handler(val) {
if (val) {
this.fetchList()
}
}
},
info: {
handler(val) {
if (val) {
this.form = val
this.dict = JSON.parse(
sessionStorage.getItem('contract_pay_log_status')
)
this.data = this.data.map(e => {
if (e.prop === 'user') {
e.value = this.form.user.name
} else {
e.value = this.form[e.prop]
}
return e
})
}
},
immediate: true
}
},
data() {
return {
page: {
page: 0,
size: 10
},
show: false,
form: null,
dict: [],
tabIndex: 0,
list: [],
columns: [
{
title: '文件名称',
dataIndex: 'name'
},
{
title: '上传人',
slotName: 'user'
},
{
title: '上传时间',
dataIndex: 'createTime'
},
{
title: '操作',
slotName: 'menu'
}
],
data: [
{
label: '回款金额',
prop: 'amount'
},
{
label: '回款日期',
prop: 'payDate'
},
{
label: '创建人',
prop: 'user'
},
{
label: '创建日期',
prop: 'createTime'
},
{
label: '备注',
prop: 'remark'
}
]
}
},
methods: {
fetchList() {
const data = { contractId: this.info.id, ...this.page, tag: 1 }
this.$api.contractFile.page(data).then(res => {
if (res.code === 200) {
this.list = res.data.records
this.page.total = res.data.total
}
})
},
success(res) {
const data = {
fileId: res.id,
name: res.fileName,
contractId: this.info.id,
tag: 1
}
this.$api.contractFile.submit(data).then(res => {
if (res.code === 200) {
this.fetchList()
this.$notification.success(res.msg)
} else {
this.$notification.error(res.msg)
}
})
}
}
}
</script>
<style lang="scss" scoped></style>

View File

@ -1,138 +0,0 @@
<template>
<div>
<div>
<add-pay :info="info" @ok="fetchList" />
</div>
<a-table :columns="columns" :data="list" class="mt-20">
<template #user="{ record }">
<div>
{{ record.user.name }}
</div>
</template>
<template #status="{ record }">
<a-tag :color="record.status.remark">
{{ record.status.label }}
</a-tag>
</template>
<template #menu="{ record }">
<div>
<pay-log-info :info="record" />
</div>
</template>
</a-table>
</div>
</template>
<script>
import payLogInfo from '@/views/contract/components/pay-log-info.vue'
import addPay from '@/views/contract/components/add-pay.vue'
export default {
components: {
addPay,
payLogInfo
},
props: {
info: {
required: true,
type: Object,
default: null
}
},
watch: {
info: {
handler(val) {
if (val) {
this.fetchList()
}
},
immediate: true
}
},
data() {
return {
page: {
page: 0,
size: 10,
total: 0
},
columns: [
{
title: '回款编号',
dataIndex: 'number'
},
{
title: '回款金额',
dataIndex: 'amount'
},
{
title: '回款日期',
dataIndex: 'payDate'
},
{
title: '创建人',
slotName: 'user'
},
{
title: '创建时间',
dataIndex: 'createTime'
},
{
title: '备注',
dataIndex: 'remark'
},
{
title: '状态',
slotName: 'status'
},
{
title: '操作',
slotName: 'menu'
}
],
list: []
}
},
methods: {
fetchList() {
const data = { contractId: this.info.id, ...this.page }
this.$api.contractPay.page(data).then(res => {
if (res.code === 200) {
this.list = res.data.records
this.page.total = res.data.total
this.fetchDict()
}
})
},
fetchDict() {
var tmp = sessionStorage.getItem('contract_pay_log_status')
if (tmp) {
const dict = JSON.parse(tmp)
this.list = this.list.map(e => {
e.status = dict.find(sub => sub.value === e.status)
return e
})
return
}
this.$api.sys
.dict({ code: 'contract_pay_log_status' })
.then(res => {
if (res.code === 200) {
const dict = res.data
sessionStorage.setItem(
'contract_pay_log_status',
JSON.stringify(dict)
)
this.list = this.list.map(e => {
e.status = dict.find(sub => sub.value === e.status)
return e
})
}
})
}
}
}
</script>
<style lang="scss" scoped></style>

View File

@ -1,96 +0,0 @@
<template>
<div>
<a-button type="primary" @click.stop="show = true">关联项目</a-button>
<a-modal
v-model:visible="show"
width="780px"
@close="reset"
@before-ok="update"
>
<a-table :columns="columns" :data="list" @row-click="checked">
<template #name="{ record }">
<div class="flex flex-center flex-justify-between">
<div>
{{ record.name }}
</div>
<div>
<icon-check-circle-fill v-if="record.checked" />
<icon-check-circle v-else class="green" />
</div>
</div>
</template>
</a-table>
</a-modal>
</div>
</template>
<script>
export default {
props: {
contractId: {
type: String,
default: ''
}
},
watch: {
show: {
handler(val) {
this.fetchList()
}
}
},
data() {
return {
show: false,
columns: [
{
title: '项目名称',
slotName: 'name'
}
],
list: [],
page: { page: 0, size: 10 }
}
},
methods: {
reset() {
this.list = this.list.map(e => {
e.checked = false
return e
})
},
checked(res) {
const index = this.list.findIndex(item => item.id === res.id)
this.list[index].checked = !this.list[index].checked
},
fetchList() {
this.$api.project.page(this.page).then(res => {
if (res.code === 200) {
this.list = res.data.records.map(e => {
e.checked = false
return e
})
}
})
},
update(done) {
const data = {
id: this.contractId,
projectIds: this.list.map(e => e.id).join(',')
}
this.$api.contract.submit(data).then(res => {
if (res.code === 200) {
this.$notification.success(res.msg)
this.$emit('ok', res.data.projects)
done()
} else {
this.$notification.error(res.msg)
done(false)
}
})
}
}
}
</script>
<style lang="scss" scoped></style>

View File

@ -1,141 +0,0 @@
<template>
<div>
<navbar title="合同库" />
<div class="container">
<div class="flex flex-center flex-justify-between">
<div class="flex flex-center flex-justify-start">
<a-input
placeholder="请输入合同名称或编号"
style="width: 380px"
allow-clear
@clear="fetchList"
v-model="name"
></a-input>
<a-button class="ml-10" type="primary" @click="fetchList"
>搜索
</a-button>
</div>
</div>
<a-table
class="mt-20"
:columns="columns"
:data="list"
:pagination="page"
@page-change="pageChange"
>
<template #customer="{ record }">
<div>
<div>{{ record.customer.name }}</div>
</div>
</template>
<template #status="{ record }">
<div v-if="record.status.label">
<a-tag :color="record.status.remark">
{{ record.status.label }}
</a-tag>
</div>
</template>
<template #menu="{ record }">
<div>
<more :id="record.id" />
</div>
</template>
</a-table>
</div>
</div>
</template>
<script>
import navbar from '@/components/navbar/index.vue'
import more from '@/views/contract/components/more.vue'
export default {
components: {
navbar,
more
},
data() {
return {
page: {
page: 0,
pageSize: 10
},
name: '',
list: [],
columns: [
{
title: '合同编号',
dataIndex: 'number'
},
{
title: '合同名称',
dataIndex: 'name'
},
{
title: '合同甲方',
slotName: 'customer'
},
{
title: '合同金额',
dataIndex: 'amountStr'
},
{
title: '合同状态',
slotName: 'status'
},
{
title: '操作',
slotName: 'menu'
}
]
}
},
mounted() {
this.fetchList()
},
methods: {
pageChange(page) {
this.page.page = page - 1
this.fetchList()
},
fetchList() {
const data = { name: this.name, ...this.page }
this.$api.contract.page(data).then(res => {
if (res.code === 200) {
this.list = res.data.records
this.fetchDict()
}
})
},
fetchDict() {
var tmp = sessionStorage.getItem('dict_contract_status')
if (tmp) {
const dict = JSON.parse(tmp)
this.list = this.list.map(item => {
item.status = dict.find(e => e.value === item.status)
item.amountStr = item.amount.toLocaleString()
return item
})
return
}
this.$api.sys.dict({ code: 'contract_status' }).then(res => {
if (res.code === 200) {
const dict = res.data
sessionStorage.setItem(
'dict_contract_status',
JSON.stringify(dict)
)
this.list = this.list.map(item => {
item.status = dict.find(e => e.value === item.status)
item.amountStr = item.amount.toLocaleString()
return item
})
}
})
}
}
}
</script>
<style lang="scss" scoped></style>

View File

@ -1,76 +0,0 @@
<template>
<div>
<navbar title="通知中心">
<template #right>
<a-button type="text" @click="readAll">全部已读</a-button>
</template>
</navbar>
<div class="container">
<a-list :bordered="false" :paginationProps="paginationProps">
<a-list-item v-for="item in list" class="grey-6">
<div class="flex flex-center flex-justify-start flex-col">
<div
class="flex flex-center full-width flex-justify-between"
>
<div
class="bold"
:class="item.status === 0 ? 'black' : 'grey'"
>
{{ item.title }}
</div>
<div>{{ item.createTime }}</div>
</div>
<div
class="flex flex-center full-width flex-justify-start mt-5"
>
{{ item.content }}
</div>
</div>
</a-list-item>
</a-list>
</div>
</div>
</template>
<script>
import navbar from '@/components/navbar/index.vue'
export default {
components: {
navbar
},
data() {
return {
list: [],
paginationProps: {
defaultPageSize: 10,
total: 0,
page: 0,
pageSize: 10
}
}
},
mounted() {
this.fetchList()
},
methods: {
fetchList() {
this.$api.notice.page(this.paginationProps).then(res => {
if (res.code === 200) {
this.list = res.data.records
this.data.page.total = res.data.total
}
})
},
readAll() {
this.$api.notice.readAll().then(res => {
if (res.code === 200) {
this.fetchList()
}
})
}
}
}
</script>
<style lang="scss" scoped></style>

View File

@ -1,101 +0,0 @@
<template>
<div>
<a-button type="outline" size="small" @click="showAdd">
<template #icon>
<icon-folder-add />
</template>
<template #default> 创建文件夹</template>
</a-button>
<a-modal
v-model:visible="show"
@close="this.$refs.form.resetFields()"
@before-ok="submit"
>
<a-form ref="form" :model="form">
<a-form-item
label="文件夹名称"
field="name"
:rules="[{ required: true, message: '请输入文件夹名称' }]"
>
<a-input
placeholder="请输入文件夹名称"
v-model="form.name"
></a-input>
</a-form-item>
</a-form>
</a-modal>
</div>
</template>
<script>
export default {
props: {
projectId: {
required: true,
type: String,
default: ''
},
queryId: {
required: true,
type: String,
default: ''
},
type:{
required: true,
type:Number,
default:0
},
pid: {
required: true,
type: String,
default: ''
}
},
data() {
return {
show: false,
form: {
name: '',
pid: '',
type: 0,
isFolder:1,
queryId: '',
projectId: ''
}
}
},
methods: {
showAdd() {
console.log(this.pid)
if (this.pid === '0') {
this.$notification.error('当前目录不应许创建文件夹')
return
}
this.show = true
},
submit(done) {
this.$refs.form.validate(errors => {
if (errors === undefined) {
this.form.pid = this.pid
this.form.projectId = this.projectId
this.form.type = this.type
this.form.queryId = this.queryId
this.$api.projectFile.submit(this.form).then(res => {
if (res.code === 200) {
done()
this.$emit('ok')
this.$notificaiton.success(res.msg)
} else{
done(false)
}
})
} else {
done(false)
}
})
}
}
}
</script>
<style lang="scss" scoped></style>

View File

@ -1,72 +0,0 @@
<template>
<div>
<a-button type="text" size="small" @click="show = true">重命名</a-button>
<a-modal v-model:visible="show" @ok="update">
<a-input placeholder="请输入名称" v-model="from.name" @input="input"></a-input>
</a-modal>
</div>
</template>
<script>
export default {
props: {
id: {
required: true,
type: String,
default: ""
},
name:{
required: true,
type: String,
default: ""
}
},
watch: {
show: {
handler(val) {
if (val){
if (this.name.indexOf(".") > -1){
this.from.extension = "."+this.name.split('.').pop()
this.from.name = this.name.substring(0, this.name.lastIndexOf('.'))
} else {
this.from.name = this.name
this.from.extension = ""
}
this.from.id = this.id
}
}
}
},
data() {
return {
show: false,
from: {
id:'',
name:'',
extension:''
}
}
},
methods: {
input(res) {
this.from.name = res
},
update(done){
const data ={id: this.id, name: this.from.name+ this.from.extension};
this.$api.projectFile.submit(data).then(res =>{
if (res.code === 200){
this.$emit("ok")
done()
} else {
this.$message.error(res.msg);
}
})
}
},
}
</script>
<style lang="scss" scoped>
</style>

View File

@ -1,267 +0,0 @@
<template>
<div>
<div class="flex flex-center flex-justify-between">
<div class="flex flex-center flex-justify-start padding">
<div class="flex flex-center">
<div>搜索文件</div>
<a-input
style="width: 420px"
placeholder="请输入文件关键词"
v-model="name"
@press-enter="fetchList"
allow-clear
@clear="fetchList"
></a-input>
</div>
<a-button class="ml-20" type="primary" @click="fetchList"
>搜索
</a-button>
</div>
<div class="flex flex-center flex-justify-start">
<a-button-group>
<a-button type="outline" size="small" @click="goHome">
<template #icon>
<icon-home />
</template>
<template #default> 首页</template>
</a-button>
<a-button type="outline" size="small" @click="goBack">
<template #icon>
<icon-nav />
</template>
<template #default> 上一级</template>
</a-button>
<upload @ok="upload" />
<add-folder
:project-id="this.projectId"
:query-id="queryId"
:type="type"
:pid="this.pid"
@ok="fetchList"
/>
</a-button-group>
</div>
</div>
<a-table
:columns="columns"
:data="list"
:loading="loading"
:pagination="page"
size="small"
@page-change="pageChange"
>
<template #fileName="{ record }">
<div class="flex flex-center flex-justify-start">
<img
v-if="record.isFolder === 1"
src="https://res.wutongshucloud.com/res/2024/12/04/202412041635423.svg"
style="width: 30px; height: 30px"
/>
<img
v-else
src="https://res.wutongshucloud.com/res/2024/12/04/202412041641902.svg"
style="width: 20px; height: 20px; padding-left: 5px"
/>
<div class="ml-10">{{ record.name }}</div>
</div>
</template>
<template #user="{record}">
<div>
{{record.user.name}}
</div>
</template>
<template #menu="{ record }">
<div class="flex flex-center">
<a-button
v-if="record.isFolder === 1"
type="text"
size="small"
@click="fetchFolder(record.id)"
>查看
</a-button>
<preview
v-else
:file-id="record.fileId"
:attach-id="record.id"
/>
<file-rename :id="record.id" :name="record.name" @ok="fetchList"></file-rename>
<a-button type="text" size="small" @click="remove(record)"
>删除
</a-button>
</div>
</template>
</a-table>
</div>
</template>
<script>
import upload from '@/components/upload/index.vue'
import preview from '@/components/preview/index.vue'
import addFolder from '@/views/project/components/attach/add-folder.vue'
import fileRename from "@/views/project/components/attach/file-rename.vue";
export default {
props: {
projectId: {
required: true,
type: String,
default: ''
},
queryId:{
required: true,
type: String,
default: ''
},
type :{
required:true,
type:Number,
default: 0
},
folder:{
type:String,
default:''
},
uploadBtn:{
type:Boolean,
default:false
}
},
components: {
upload,
preview,
addFolder,
fileRename
},
data() {
return {
name: '',
loading: true,
history: ['0'],
page: {
page: 0,
pageSize: 10,
total: 0
},
list: [],
pid: '0',
columns: [
{
title: '名称',
slotName: 'fileName'
},
{
title: '创建时间',
dataIndex: 'createdAt'
},
{
title: '创建人',
slotName: 'user'
},
{
title: '操作',
slotName: 'menu'
}
]
}
},
mounted() {
if (this.folder !== ""){
this.fetchInit()
} else {
this.fetchList()
}
},
methods: {
goHome() {
this.history = ['0']
this.pid = '0'
this.fetchList()
},
goBack() {
var size = this.history.length
if (size > 1) {
this.history = this.history.slice(0, size - 1)
this.pid = this.history[this.history.length - 1]
this.fetchList()
} else {
this.$notification.info('已经回到首页')
}
},
fetchFolder(id) {
this.pid = id
this.history.push(id)
this.fetchList()
},
pageChange(page) {
this.page.page = page
this.fetchList()
},
fetchInit() {
this.$api.sys.dict({ code: this.folder }).then(res => {
if (res.code === 200) {
var folder = res.data.map(e => e.label)
this.$api.projectFile
.initFolder({
projectId: this.projectId,
folders: folder.join(','),
type: this.type,
queryId: this.queryId
})
.then(() => {
this.fetchList()
this.loading = false
})
}
})
},
fetchList() {
const data = {
name: this.name,
projectId: this.projectId,
pid: this.pid,
type: this.type,
queryId: this.queryId,
...this.page
}
this.$api.projectFile.page(data).then(res => {
this.loading = false
if (res.code === 200) {
this.list = res.data.records
this.page.total = res.data.total
}
})
},
upload(file) {
const data = { projectId: this.projectId, pid: this.pid, name: file.fileName, type: this.type, fileId: file.id,queryId: this.queryId }
this.$api.projectFile.submit(data).then(res => {
if (res.code === 200) {
this.fetchList()
this.$notification.success(res.msg)
} else {
this.$notification.error(res.msg)
}
})
},
remove(file) {
if (file.pid === '0') {
this.$notification.error('当前内容不支持删除')
return
}
this.$api.projectFile.remove({ id: file.id }).then(res => {
if (res.code === 200) {
this.$notification.success(res.msg)
this.fetchList()
} else {
this.$notification.error(res.msg)
}
})
}
}
}
</script>
<style lang="scss" scoped></style>

View File

@ -1,114 +0,0 @@
<template>
<div>
<a-button class="ml-10" type="primary" size="small" @click="show = true"
>选择联系人
</a-button>
<a-modal v-model:visible="show" width="780px" @before-ok="submit">
<div class="flex flex-center flex-justify-between">
<div class="flex flex-center flex-justify-start">
<a-input
placeholder="请输入联系人姓名搜索"
style="width: 280px"
size="small"
></a-input>
<a-button type="primary" class="ml-20" size="small"
>搜索
</a-button>
</div>
<edit-contacts :customer-id="customerId" @ok="fetchList" />
</div>
<a-table
class="mt-20"
:columns="columns"
:data="list"
@row-click="checked"
>
<template #name="{ record }">
<div>{{ record.name }} {{ record.phone }}</div>
</template>
<template #menu="{ record }">
<div>
<icon-check-circle-fill v-if="record.checked" />
<icon-check-circle v-else class="green" />
</div>
</template>
</a-table>
</a-modal>
</div>
</template>
<script>
import editContacts from '@/views/base/customer/components/edit.vue-contacts.vue'
export default {
components: {
editContacts
},
props: {
customerId: {
required: true,
type: String,
default: ''
}
},
watch: {
show: {
handler(val) {
if (val) {
this.fetchList()
}
}
}
},
data() {
return {
page: {
page: 0,
size: 10,
total: 0
},
show: false,
list: [],
checkList: [],
columns: [
{
title: '姓名',
slotName: 'name'
},
{
title: '操作',
slotName: 'menu'
}
]
}
},
methods: {
checked(row) {
row.checked = !row.checked
if (row.checked) {
this.checkList.push(row)
} else {
this.checkList = this.checkList.filter(e => e.id !== row.id)
}
},
fetchList() {
const data = { customerId: this.customerId, ...this.page }
this.$api.contacts.page(data).then(res => {
if (res.code === 200) {
this.list = res.data.records.map(e => {
e.checked = false
return e
})
this.page.total = res.data.total
}
})
},
submit(done) {
this.$emit('ok', this.checkList)
done()
}
}
}
</script>
<style lang="scss" scoped></style>

View File

@ -1,206 +0,0 @@
<template>
<div>
<a-button type="primary" size="small" @click="show = true">
<template #icon>
<icon-upload />
</template>
<template #default> 上传附件</template>
</a-button>
<a-modal
width="860px"
v-model:visible="show"
:mask-closable="false"
:title="`已经选择(` + checkList.length + `)个附件`"
:title-align="'start'"
@before-ok="submit"
@close="reset"
>
<div class="flex flex-center flex-justify-between">
<div class="flex flex-center flex-justify-start">
<a-input
placeholder="请输入文件名称"
style="max-width: 380px"
></a-input>
<a-button class="ml-10" type="primary">搜索</a-button>
</div>
<div>
<a-button-group>
<a-button type="outline" size="small" @click="goHome">
<template #icon>
<icon-home />
</template>
<template #default> 首页</template>
</a-button>
<a-button type="outline" size="small" @click="goBack">
<template #icon>
<icon-nav />
</template>
<template #default> 上一级</template>
</a-button>
<upload @ok="upload" />
</a-button-group>
</div>
</div>
<a-table
class="mt-20"
:columns="columns"
:data="list"
size="small"
:pagination="page"
@page-change="pageChange"
@row-click="rowClick"
>
<template #name="{ record }">
<div class="flex flex-center flex-justify-start">
<img
v-if="record.type === 1"
src="https://res.wutongshucloud.com/res/2024/12/04/202412041635423.svg"
style="width: 30px; height: 30px"
/>
<img
v-else
src="https://res.wutongshucloud.com/res/2024/12/04/202412041641902.svg"
style="width: 20px; height: 20px; padding-left: 5px"
/>
<div class="ml-10">
{{ record.name }}
</div>
</div>
</template>
<template #menu="{ record }">
<div
v-if="record.type === 0"
style="width: 80px"
class="flex flex-center flex-justify-start"
>
<icon-check-circle-fill v-if="record.checked" />
<icon-check-circle v-else class="green" />
</div>
</template>
</a-table>
</a-modal>
</div>
</template>
<script>
import upload from '@/components/upload/index.vue'
export default {
components: {
upload
},
props: {
projectId: {
required: true,
type: String,
default: ''
}
},
watch: {
show: {
handler(val) {
if (val) {
this.fetchList()
}
}
}
},
data() {
return {
show: false,
pid: '0',
page: {
page: 0,
pageSize: 10,
total: 0
},
list: [],
checkList: [],
history: ['0'],
columns: [
{
title: '名称',
slotName: 'name'
},
{
title: '选择',
slotName: 'menu'
}
]
}
},
methods: {
rowClick(row) {
if (row.type === 0) {
row.checked = !row.checked
if (row.checked) {
this.checkList.push(row)
} else {
this.checkList = this.checkList.filter(e => e.id !== row.id)
}
} else {
this.pid = row.id
this.history.push(row.id)
this.fetchList()
}
},
fetchList() {
const data = {
projectId: this.projectId,
pid: this.pid,
...this.page
}
this.$api.projectFile.page(data).then(res => {
if (res.code === 200) {
this.list = res.data.records.map(e => {
e.checked = false
return e
})
this.page.total = res.data.total
}
})
},
submit(done) {
this.$emit('ok', this.checkList)
done()
},
goHome() {
this.history = ['0']
this.pid = '0'
this.fetchList()
},
goBack() {
var size = this.history.length
if (size > 1) {
this.history = this.history.slice(0, size - 1)
this.pid = this.history[this.history.length - 1]
this.fetchList()
} else {
this.$notification.info('已经回到首页')
}
},
pageChange(page) {
this.page.page = page - 1
this.fetchList()
},
upload(file) {
const data = { projectId: this.projectId, pid: this.pid, ...file }
this.$api.projectFile.submit(data).then(res => {
if (res.code === 200) {
this.fetchList()
this.$notification.success(res.msg)
} else {
this.$notification.error(res.msg)
}
})
},
reset() {
this.checkList.length = 0
this.history = ['0']
this.pid = '0'
}
}
}
</script>
<style lang="scss" scoped></style>

View File

@ -1,357 +0,0 @@
<template>
<div>
<a-button type="primary" @click.stop="show = true"
>{{ info ? '编辑' : '新增合同' }}
</a-button>
<a-modal
v-model:visible="show"
width="960px"
title="新增合同"
title-align="start"
@close="reset"
@before-ok="submit"
>
<a-form auto-label-width :model="form" ref="form">
<a-row :gutter="16">
<a-col :span="24">
<a-form-item
label="合同名称"
field="name"
:rules="[
{ required: true, message: '请输入合同名称' }
]"
>
<a-input
placeholder="请输入合同名称"
v-model="form.name"
></a-input>
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="16">
<a-col :span="12">
<a-form-item
label="合同编号"
field="number"
:rules="[
{ required: true, message: '请输入合同编号' }
]"
>
<a-input
placeholder="请输入合同编号"
v-model="form.number"
></a-input>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item
field="type"
label="合同类型"
:rules="[
{ required: true, message: '请选择合同类型' }
]"
>
<a-select
:options="contractOptions"
allow-search
@focus="handleContractSearch"
placeholder="请选择合同负责人"
v-model="form.type"
></a-select>
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="16">
<a-col :span="12">
<a-form-item
label="合同金额"
field="amount"
:rules="[
{ required: true, message: '请输入合同金额' }
]"
>
<a-input-number
v-model="form.amount"
placeholder="请输入合同金额"
></a-input-number>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="签订时间" field="signDate">
<a-date-picker
v-model="form.signDate"
class="full-width"
placeholder="请选择签订时间"
></a-date-picker>
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="16">
<a-col :span="12">
<a-form-item label="合同开始日期" field="startDate">
<a-date-picker
class="full-width"
v-model="form.startDate"
placeholder="请选择合同开始日期"
></a-date-picker>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="合同结束日期" field="endDate">
<a-date-picker
v-model="form.endDate"
class="full-width"
placeholder="请选择合同结束日期"
></a-date-picker>
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="16">
<a-col :span="12">
<a-form-item
label="对方签约单位"
field="customerId"
:rules="[
{ required: true, message: '请选择合同客户' }
]"
>
<a-select
allow-search
:options="customerOptions"
@search="handleCustomer"
v-model="form.customerId"
placeholder="请选择合同客户"
></a-select>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item
label="对方签约负责人"
field="contact"
>
<a-select
allow-search
:options="customerContactsOptions"
@search="handleContacts"
v-model="form.contact"
placeholder="请选择客户签约人"
></a-select>
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="16">
<a-col :span="12">
<a-form-item
field="orgValue"
label="我方签约单位"
:rules="[
{ required: true, message: '请选择我方签约单位' }
]"
>
<a-select
:options="companyOptions"
allow-search
@focusin="handleCompanyFocus"
placeholder="请选择我方签约单位"
v-model="form.orgValue"
></a-select>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item
field="person"
label="我方签约负责人"
:rules="[
{ required: true, message: '请选择合同负责人' }
]"
>
<a-select
:options="userOptions"
allow-search
@search="handleSearch"
@focusin="handleFocus"
placeholder="请选择合同负责人"
v-model="form.person"
></a-select>
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="16">
<a-col :span="24">
<a-form-item label="合同备注" field="remark">
<a-textarea
v-model="form.remark"
:auto-size="{ minRows: 5 }"
placeholder="请输入合同备注"
></a-textarea>
</a-form-item>
</a-col>
</a-row>
</a-form>
</a-modal>
</div>
</template>
<script>
export default {
props: {
projectId: {
required: true,
type: String,
default: ""
},
taskId :{
required: true,
type: String,
default: ""
}
},
watch: {
show: {
handler(val) {
if (val && this.info) {
this.form = { ...this.info }
this.handleSearch(this.form.person.name)
this.form.person = this.form.person.id
this.handleCustomer(this.form.customer.name)
this.form.customerId = this.form.customer.id
if (this.form.signatory) {
this.handleSign(this.form.signatory.name)
this.form.signatory = this.form.signatory.id
}
if (this.form.customerContact) {
this.handleContacts(this.form.customerContact.name)
this.form.customerContactId =
this.form.customerContact.id
}
}
}
}
},
data() {
return {
show: false,
form: {
projectId:'',
name:'',
number:'',
amount:0,
type :'0',
customerId:'',
contact:'',
orgValue:'',
person:'',
remark:'',
signDate:'',
startDate:'',
endDate:'',
taskIds:''
},
userOptions: [],
signOptions: [],
contractOptions: [],
customerOptions: [],
customerContactsOptions: [],
companyOptions:[]
}
},
methods: {
//
handleSearch(value) {
this.$api.user.list({ name: value }).then(res => {
if (res.code === 200) {
this.userOptions = res.data.map(e => {
return { label: e.name, value: e.id }
})
}
})
},
handleSign(value) {
this.$api.user.list({ name: value }).then(res => {
if (res.code === 200) {
this.signOptions = res.data.map(e => {
return { label: e.name, value: e.id }
})
}
})
},
handleContractSearch(){
this.$api.sys.dict({code:'contract_type'}).then(res => {
if (res.code === 200){
this.contractOptions = res.data.map(e => {
return { label: e.label, value: e.value }
})
}
})
},
handleCompanyFocus(){
this.$api.sys.dict({code:'contract_sign_company'}).then(res => {
if (res.code === 200){
this.companyOptions = res.data.map(e => {
return { label: e.label, value: e.value }
})
}
})
},
handleContacts(value) {
this.$api.contacts
.list({ name: value, customerId: this.form.customerId })
.then(res => {
if (res.code === 200) {
this.customerContactsOptions = res.data.map(item => {
return { label: item.name, value: item.id }
})
}
})
},
handleCustomer(value) {
this.$api.customer.all({ name: value }).then(res => {
if (res.code === 200) {
this.customerOptions = res.data.map(e => {
return { label: e.name, value: e.id }
})
}
})
},
handleFocus() {
this.handleSearch('')
},
reset() {
if (!this.form.id) {
this.$refs.form.resetFields()
}
},
submit(done) {
this.$refs.form.validate(errors => {
if (errors === undefined) {
this.form.projectId = this.projectId
this.form.taskIds = [this.taskId]
this.$api.contract.submit(this.form).then(res => {
if (res.code === 200) {
this.$notification.success(res.msg)
this.$emit('ok', res.data)
done()
} else {
this.$notification.error(res.msg)
done(false)
}
})
} else {
done(false)
}
})
}
}
}
</script>
<style lang="scss" scoped></style>

View File

@ -1,154 +0,0 @@
<template>
<div>
<div>
<a-button-group type="outline">
<add-contract :project-id="projectId" :task-id="taskId" @ok="fetchInfo"/>
<a-button>关联合同</a-button>
</a-button-group>
</div>
<a-card class="mt-20">
<a-descriptions
v-if="info"
:data="data"
:title="info.name"
bordered
/>
<a-empty v-else description="暂无合同">
</a-empty>
</a-card>
<div>
<a-tabs class="mt-10" @change="tabChange" :active-key="tabIndex">
<a-tab-pane title="合同附件" key="0"></a-tab-pane>
<a-tab-pane title="合同回款" key="1"></a-tab-pane>
</a-tabs>
</div>
<div v-if="tabIndex === 0 && info">
<attach :type="2" :query-id="info.id" :project-id="info.projectId"/>
</div>
<a-empty v-else description="暂无数据">
</a-empty>
</div>
</template>
<script>
import EditContract from '@/views/project/contract/components/edit.vue-contract.vue'
import attach from "@/views/project/components/attach/index.vue";
export default {
components: {
addContract: EditContract,attach
},
props: {
projectId: {
required: true,
type: String,
default: ''
},
taskId: {
required: true,
type: String,
default: ''
}
},
watch: {
tabIndex: {
handler(val) {
if (val === 0) {
this.fetchInfo()
}
}
}
},
data() {
return {
tabIndex: 0,
info: null,
data: [
{
label: '合同编号',
prop: 'number'
},
{
label: '合同类型',
prop: 'number'
},
{
label: '合同金额 单位:元',
prop: 'amount'
},
{
label: '签订时间',
prop: 'signDate'
},
{
label: '合同开始日期',
prop: 'startDate'
},
{
label: '合同结束日期',
prop: 'endDate'
},
{
label: '对方单位名称',
prop: 'customer'
},
{
label: '对方单位联系人',
prop: 'contact'
},
{
label: '我方单位名称',
prop: 'org'
},
{
label: '我方负责联系人',
prop: 'person'
},
{
label: '备注',
prop: 'remark'
}
]
}
},
mounted() {
this.fetchInfo()
},
methods: {
fetchInfo() {
this.$api.contract.info({ taskId: this.taskId }).then(res => {
if (res.code === 200) {
this.info = res.data
this.fetchData()
}
})
},
fetchData() {
this.data = this.data.map(e => {
const item = e
item.value = this.info[e.prop]
if (e.prop === "person"){
item.value = this.info.personInfo.name
}
if (e.prop === "org"){
item.value = this.info.org.label
}
if (e.prop === "customer"){
item.value = this.info.customer.name
}
if (e.prop === "contact"){
item.value = this.info.contact.name
}
return item
})
},
tabChange(res) {}
}
}
</script>
<style lang="scss" scoped></style>

View File

@ -1,178 +0,0 @@
<template>
<div class="mt-20">
<div class="flex flex-center flex-justify-between">
<h2>业主单位{{ info.customer.name }}</h2>
<contacts-picker :customer-id="info.customer.id" @ok="success" />
</div>
<a-divider />
<a-list>
<a-list-item v-for="item in contactlist">
<div class="flex flex-center flex-justify-start">
<div>
{{ item.name }} {{ item.phone }}
<a-tag color="red" class="ml-20"
>{{ (item.sex = '0' ? '男' : '女') }}
</a-tag>
</div>
<div class="ml-20">{{ item.post }}</div>
</div>
</a-list-item>
</a-list>
<div class="flex flex-center flex-justify-between mt-20">
<div class="flex flex-center flex-justify-start">
<div class="flex flex-center flex-justify-start">
<h2>实施单位</h2>
<h2 v-if="edit === false && info.construction">
{{ constructionName }}
</h2>
<a-select
class="ml-10"
v-if="edit"
size="small"
allow-search
:options="options"
v-model="constructionId"
style="width: 380px"
@search="handleSearch"
></a-select>
</div>
<div class="ml-10">
<icon-edit v-if="edit === false" @click="edit = true" />
<icon-save v-else @click="save" />
</div>
</div>
<contacts-picker
v-if="constructionId"
:customer-id="constructionId"
@ok="successConstruction"
/>
</div>
<a-divider />
<a-list size="small">
<a-list-item v-for="item in constructionContactlist">
<div class="flex flex-center flex-justify-start">
<div>
{{ item.name }} {{ item.phone }}
<a-tag color="red" class="ml-20"
>{{ (item.sex = '0' ? '男' : '女') }}
</a-tag>
</div>
<div class="ml-20">{{ item.post }}</div>
</div>
</a-list-item>
</a-list>
</div>
</template>
<script>
import contactsPicker from '@/views/project/components/contacts-picker/index.vue'
import debounce from '@/utils/index.js'
export default {
components: {
contactsPicker
},
props: {
info: {
type: Object,
default: null
}
},
watch: {
info: {
handler(val) {
if (val) {
this.constructionName = val.construction.name
this.constructionId = val.construction.id
this.contactlist = val.contacts
this.constructionContactlist = val.constructionContacts
}
},
immediate: true
}
},
data() {
return {
edit: false,
contactlist: [],
constructionContactlist: [],
constructionId: '',
constructionName: '',
options: []
}
},
mounted() {},
methods: {
success(list) {
this.contactlist = this.contactlist.concat(list)
this.contactlist = Array.from(
new Map(this.contactlist.map(item => [item.id, item])).values()
)
const data = {
id: this.info.id,
contacts: this.contactlist.map(e => e.id).join(',')
}
this.$api.project.submit(data).then(res => {
if (res.code === 200) {
this.$notification.success(res.msg)
} else {
this.$notification.error(res.msg)
}
})
},
successConstruction(list) {
this.constructionContactlist =
this.constructionContactlist.concat(list)
this.constructionContactlist = Array.from(
new Map(
this.constructionContactlist.map(item => [item.id, item])
).values()
)
const data = {
id: this.info.id,
constructionContacts: this.constructionContactlist
.map(e => e.id)
.join(',')
}
this.$api.project.submit(data).then(res => {
if (res.code === 200) {
this.$notification.success(res.msg)
} else {
this.$notification.error(res.msg)
}
})
},
handleSearch(res) {
debounce(() => {
this.$api.customer.all({ name: res }).then(res => {
if (res.code === 200) {
this.options = res.data.map(e => {
return { label: e.name, value: e.id }
})
}
})
}, 800)
},
save() {
if (this.constructionId) {
const data = {
id: this.info.id,
constructionId: this.constructionId
}
this.$api.project.submit(data).then(res => {
if (res.code === 200) {
this.constructionName = res.data.construction.name
this.edit = false
this.notification.success(res.msg)
} else {
this.notification.error(res.msg)
}
})
}
}
}
}
</script>
<style lang="scss" scoped></style>

View File

@ -1,92 +0,0 @@
<template>
<div>
<div class="full-width flex flex-center flex-justify-start">
<h2>项目所属地区</h2>
</div>
<a-cascader
class="mt-20"
placeholder="请选择所属地区"
:options="options"
allow-search
v-model="city"
:field-names="{
label: 'name',
value: 'code'
}"
/>
<div v-if="city === ''">
<div style="height: 500px" class="flex flex-center">
<a-button>请选择地区</a-button>
</div>
</div>
<div class="mt-20">
<div
v-for="(item, index) in customerList"
:key="item.id"
class="padding border-bottom"
:class="activeIndex === index ? 'hover-bg' : ''"
@click="change(index)"
>
<div class="flex flex-center flex-justify-start">
<div
class="font-14 bold text-left flex full-width flex-justify-start"
>
{{ item.name }}
</div>
<div class="flex flex-center">
<a-tag color="blue"
>项目{{ item.projectCount }}
</a-tag>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
watch: {
city(val) {
this.$emit('ok', val)
if (val.length > 0) {
this.fetchCustomerByCity(val)
}
}
},
data() {
return {
options: [],
city: '',
activeIndex: 0,
customerList: []
}
},
mounted() {
this.fetchCity()
},
methods: {
fetchCustomerByCity(code) {
this.$api.customer.findList({ code: code }).then(res => {
if (res.code === 200) {
this.customerList = res.data
this.$emit('ok', this.customerList[0])
}
})
},
fetchCity() {
this.$api.base.areaTree({ code: '53' }).then(res => {
if (res.code === 200) {
this.options = res.data
}
})
},
change(index) {
this.activeIndex = index
this.$emit('ok', this.customerList[index])
}
}
}
</script>
<style lang="scss" scoped></style>

View File

@ -1,178 +0,0 @@
<template>
<div>
<a-button type="primary" size="small" @click="show = true">
<template #icon>
<icon-plus />
</template>
<!-- Use the default slot to avoid extra spaces -->
<template #default>新建</template>
</a-button>
<a-modal
v-model:visible="show"
width="720px"
@close="this.$refs.form.resetFields()"
@before-ok="submit"
>
<a-form :model="form" auto-label-width ref="form">
<a-form-item
label="项目名称"
field="name"
:rules="[{ required: true, message: '请输入项目名称' }]"
>
<a-input
placeholder="请输入项目名称"
v-model="form.name"
></a-input>
</a-form-item>
<a-form-item
label="项目总投"
field="amount"
:rules="[{ required: true, message: '请输入项目总投' }]"
>
<a-input-number
placeholder="请输入项目总投"
v-model="form.amount"
>
<template #suffix>
<div>万元</div>
</template>
</a-input-number>
</a-form-item>
<a-form-item
field="cityCode"
label="项目地区"
:rules="[{ required: true, message: '请选择项目地区' }]"
>
<a-cascader
placeholder="请选择项目地区"
:options="options"
allow-search
v-model="form.cityCode"
:field-names="{
label: 'name',
value: 'code'
}"
/>
</a-form-item>
<a-form-item
label="业主单位"
field="customerId"
:rules="[{ required: true, message: '请选择业主单位' }]"
>
<a-select
placeholder="请选择业主单位"
:options="customerList"
allow-search
@search="fetchCustomer"
v-model="form.customerId"
></a-select>
</a-form-item>
<a-form-item
label="行业分类"
field="industry"
:rules="[{ required: true, message: '请选择行业分类' }]"
>
<a-cascader
v-model="form.industry"
allow-search
placeholder="请输入项目名称"
:options="industry"
></a-cascader>
</a-form-item>
<a-form-item
label="建设内容及规模"
field="content"
:rules="[
{ required: true, message: '请输入建设内容及规模' }
]"
>
<a-textarea
placeholder="建设内容及规模"
v-model="form.content"
:auto-size="{ minRows: 5 }"
></a-textarea>
</a-form-item>
</a-form>
</a-modal>
</div>
</template>
<script>
export default {
watch: {
show: {
handler(val) {
if (val) {
this.fetchCity()
this.fetchDict()
}
}
}
},
data() {
return {
industry: [],
options: [],
form: {
name: '',
amount: '',
cityCode: '',
customerId: '',
industry: '',
createUserId: ''
},
customerList: [],
show: false
}
},
mounted() {
var user = JSON.parse(localStorage.getItem('user'))
this.form.createUserId = user.id
},
methods: {
fetchCity() {
this.$api.base.areaTree({code:"53"}).then(res => {
if (res.code === 200) {
this.options = res.data
}
})
},
fetchDict() {
this.$api.sys.dict({ code: 'project_industry_type' }).then(res => {
if (res.code === 200) {
this.industry = res.data
}
})
},
fetchCustomer(res) {
this.$api.customer.findList({ name: res }).then(res => {
if (res.code === 200) {
this.customerList = res.data.map(e => {
return { label: e.name, value: e.id }
})
}
})
},
submit(done) {
this.$refs.form.validate(errors => {
if (errors === undefined) {
this.$api.project.submit(this.form).then(res => {
if (res.code === 200) {
this.$notification.success(res.msg)
this.$emit('ok')
done()
} else {
this.$notification.error(res.msg)
done(false)
}
})
} else {
done(false)
}
})
}
}
}
</script>
<style lang="scss" scoped></style>

View File

@ -1,182 +0,0 @@
<template>
<div>
<a-button size="small" type="primary" @click="show = true">
<template #icon>
<icon-edit />
</template>
创建任务
</a-button>
<a-modal
v-model:visible="show"
width="760px"
@close="this.$refs.form.resetFields()"
@before-ok="submit"
>
<a-form auto-label-width :model="form" ref="form">
<a-row gutter="16">
<a-col :span="12">
<a-form-item
label="优先级"
:rules="[
{ required: true, message: '请选择优先级' }
]"
field="level"
>
<a-select
:options="levelOptions"
v-model="form.level"
placeholder="请选择优先级"
/>
</a-form-item>
</a-col>
</a-row>
<a-form-item
label="任务周期"
:rules="[{ required: true, message: '请选择任务周期' }]"
field="time"
>
<a-range-picker style="width: 100%" v-model="form.time" />
</a-form-item>
<a-row gutter="16">
<a-col :span="12">
<a-form-item
label="任务标签"
:rules="[
{ required: true, message: '请选择任务标签' }
]"
field="tag"
>
<a-select
:options="tagsOptions"
v-model="form.tag"
placeholder="请选择任务标签"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item
label="执行人"
:rules="[
{ required: true, message: '请选择执行人' }
]"
field="executors"
>
<a-select
multiple
:options="userOptions"
allow-search
@search="handleSearch"
@focusin="handleFocus"
v-model="form.executors"
placeholder="请选择执行人"
/>
</a-form-item>
</a-col>
</a-row>
<a-form-item label="任务描述" field="remark">
<a-textarea
v-model="form.remark"
placeholder="请添加任务描述"
:auto-size="{ minRows: 4 }"
/>
</a-form-item>
</a-form>
</a-modal>
</div>
</template>
<script>
export default {
props: {
projectId: {
required: true,
type: String,
default: ''
}
},
watch: {
show: {
handler(val) {
if (val) {
this.form.projectId = this.projectId
this.fetchDict()
}
}
}
},
data() {
return {
levelOptions: [],
tagsOptions: [],
userOptions: [],
show: false,
form: {
projectId: '',
level: '2',
time: '',
tag: '',
executors: null,
remark: '',
}
}
},
methods: {
fetchDict() {
this.$api.sys.dict({ code: 'project_task_level' }).then(res => {
if (res.code === 200) {
this.levelOptions = res.data.map(e => {
return { label: e.label, value: e.value }
})
}
})
this.$api.sys.dict({ code: 'project_task_type' }).then(res => {
if (res.code === 200) {
this.tagsOptions = res.data.map(e => {
return { label: e.label, value: e.value }
})
}
})
},
handleFocus(e) {
this.handleSearch('')
},
handleSearch(value) {
this.$api.user.list({ name: value }).then(res => {
if (res.code === 200) {
this.userOptions = res.data.map(e => {
return { label: e.name, value: e.id }
})
}
})
},
submit(done) {
this.$refs.form.validate(errors => {
if (errors === undefined) {
const data = { ...this.form }
data.startDate = data.time[0]
data.endDate = data.time[1]
data.executorIds = data.executors
delete data.executors
this.$api.task.submit(data).then(res => {
if (res.code === 200) {
this.$notification.success(res.msg)
this.$emit('ok')
done()
} else {
this.$notification.error(res.msg)
done(false)
}
})
} else {
done(false)
}
})
}
}
}
</script>
<style lang="scss" scoped></style>

View File

@ -1,219 +0,0 @@
<template>
<div>
<a-button type="text" size="small" @click="show = true">更多</a-button>
<a-drawer
v-if="info"
v-model:visible="show"
width="80%"
:mask-closable="false"
:header="false"
:footer="false"
>
<div>
<div class="flex flex-center flex-justify-between">
<div class="flex flex-center">
<div class="font-18 bold" v-if="edit === false">
{{ name }}
</div>
<div v-else>
<a-input
v-model="name"
style="width: 480px"
></a-input>
</div>
<icon-edit
class="padding pointer"
v-if="edit === false"
@click="edit = true"
/>
<icon-save
class="padding pointer"
v-else
@click="updateName"
/>
</div>
<a-button type="outline" size="small" @click="show = false"
>关闭
</a-button>
</div>
</div>
<div class="mt-20 flex flex-center flex-justify-start">
<edit-task
:project-id="info.id"
@ok="this.$refs.task.fetchList()"
/>
</div>
<div class="mt-20">
<a-descriptions
:data="data"
bordered
:column="{ xs: 1, md: 3 }"
>
<a-descriptions-item
v-for="item of data"
:label="item.label"
:span="3"
>
<div>{{ item.value }}</div>
</a-descriptions-item>
</a-descriptions>
</div>
<a-tabs class="mt-10" @change="tabChange" :active-key="tabIndex">
<a-tab-pane title="项目任务" key="0"></a-tab-pane>
<a-tab-pane title="项目文件" key="1"></a-tab-pane>
<a-tab-pane title="跟进记录" key="2"></a-tab-pane>
</a-tabs>
<div v-if="tabIndex === 0">
<task :project-id="info.id" ref="task" />
</div>
<div v-else-if="tabIndex === 1">
<attach :project-id="info.id" :query-id="info.id" :type="0" folder="project_folder_init"/>
</div>
<div v-else-if="tabIndex === 4">
<base-info :info="info" />
</div>
<div
v-else
class="flex flex-center flex-col grey-6"
style="margin-top: 96px"
>
<img
style="width: 100px"
src="https://res.wutongshucloud.com/res/2024/12/09/202412091020938.svg"
/>
<div>正在开发中</div>
</div>
</a-drawer>
</div>
</template>
<script>
import task from '@/views/project/index/components/task.vue'
import editTask from '@/views/project/index/components/edit.vue-task.vue'
import baseInfo from '@/views/project/index/components/base-info.vue'
import attach from "@/views/project/components/attach/index.vue";
export default {
components: {
task,
editTask,
attach,
baseInfo
},
props: {
id: {
required: true,
type: String,
default: ""
}
},
watch: {
show: {
handler(val) {
if (val) {
this.fetchInfo()
this.tabIndex = 0
} else {
this.tabIndex = 0
}
},
immediate: true
},
},
data() {
return {
info:null,
name: '',
edit: false,
show: false,
tabIndex: 0,
data: [
{
label: '项目总投资(万元)',
prop: 'amount'
},
{
label: '项目负责人',
prop: 'createUser'
},
{
label: '项目地区',
prop: 'cityName'
},
{
label: '所属行业',
prop: 'industry'
},
{
label: '业主单位',
prop: 'customer'
},
{
label: '建设内容及规模',
prop: 'content',
span: 3
}
]
}
},
methods: {
fetchInfo(){
this.$api.project.info({id:this.id}).then(res => {
if (res.code === 200){
this.info = res.data
this.name = this.info.name
this.fetchData()
}
})
},
fetchData() {
this.data = this.data.map(item => {
const res = {
label: item.label,
value: this.info[item.prop],
prop: item.prop,
span: item.span ?? 1
}
if (item.prop === 'createUser') {
res.value = this.info.user.name
}
if (item.prop === 'customer') {
res.value = this.info.customer
? this.info.customer.name
: ''
}
if (item.prop === 'cityName') {
res.value = this.info.region
? this.info.region.province_name + this.info.region.city_name + this.info.region.name
: ''
}
if (item.prop === 'industry') {
res.value = this.info.industry
? this.info.industry.label
: ''
}
return res
})
},
tabChange(index) {
this.tabIndex = Number.parseInt(index)
},
updateName() {
const data = { id: this.id, name: this.name }
this.edit = false
this.$api.project.submit(data).then(res => {
if (res.code === 200) {
this.$notification.success(res.msg)
} else {
this.$notification.error(res.msg)
}
})
}
}
}
</script>
<style lang="scss" scoped></style>

View File

@ -1,120 +0,0 @@
<template>
<div>
<a-table :columns="columns" :data="list">
<template #level="{ record }">
<div>
{{ record.level.label }}
</div>
</template>
<template #user="{ record }">
<div>
{{ record.user.name }}
</div>
</template>
<template #executors="{ record }">
<div>
<a-avatar-group :size="32">
<view v-for="item in record.executors ">
<a-avatar v-if="item.avatar" :style="{ backgroundColor: '#7BC616' }">
<img alt="avatar" :src="item.avatar" />
</a-avatar>
<a-avatar v-else :style="{ backgroundColor: '#7BC616' }">{{item.name.substring(0,1)}}</a-avatar>
</view>
</a-avatar-group>
</div>
</template>
<template #status="{ record }">
<div>
{{ record.status.label }}
</div>
</template>
<template #tag="{ record }">
<div>
<a-tag color="blue">{{ record.tag.label }}</a-tag>
</div>
</template>
<template #menu="{ record }">
<div>
<task-info :id="record.id" :info="record"/>
</div>
</template>
</a-table>
</div>
</template>
<script>
import taskInfo from '@/views/project/task/task-info.vue'
export default {
components: {
taskInfo
},
props: {
projectId: {
required: true,
type: String,
default: ''
}
},
data() {
return {
list: [],
page: { page: 0, size: 10, total: 0 },
dict: [],
level: [],
columns: [
{
title: '描述',
dataIndex: 'remark'
},
{
title: '优先级',
slotName: 'level'
},
{
title: '任务标签',
slotName: 'tag'
},
{
title: '任务状态',
slotName: 'status'
},
{
title: '创建时间',
dataIndex: 'createdAt'
},
{
title: '创建人',
slotName: 'user'
},
{
title: '执行人',
slotName: 'executors'
},
{
title: '操作',
slotName: 'menu'
}
]
}
},
mounted() {
this.fetchList()
},
methods: {
fetchList() {
const data = { projectId: this.projectId, ...this.page }
this.$api.task.page(data).then(res => {
if (res.code === 200) {
this.list = res.data.records.map(e => {
e.status.remark = JSON.parse(e.status.remark)
return e
})
}
})
}
}
}
</script>
<style lang="scss" scoped></style>

View File

@ -1,160 +0,0 @@
<template>
<div>
<navbar title="项目库" />
<div class="flex">
<div class="container" style="min-width: 320px">
<city-tree @ok="changeCustomer" />
</div>
<div class="container full-width">
<div class="flex flex-center flex-justify-between full-width">
<div class="flex flex-center flex-justify-between full-width">
<div v-if="city" >
<div class="flex flex-center flex-justify-start full-width">
<h2>{{ city.name }}</h2>
</div>
<div
class="mt-10 flex flex-center flex-justify-start full-width"
>
<a-tag color="blue"
>共计项目 {{ city.projectCount }} 待办任务
{{ city.taskCount }}
</a-tag>
</div>
</div>
</div>
<div class="flex flex-center flex-justify-between">
<div>
<edit-project @ok="fetchList"/>
</div>
</div>
</div>
<div>
</div>
<div class="flex flex-center flex-justify-between mt-20">
<div class="flex flex-center" >
<a-input placeholder="请输入项目名称" v-model="name" allow-clear> </a-input>
<a-button type="primary" class="ml-20" @click="fetchList"> 搜索</a-button>
</div>
<div></div>
</div>
<a-table
:columns="columns"
:data="list"
class="mt-20"
:pagination="page"
@page-change="pageChange"
>
<template #user="{ record }">
<div>
{{ record.user.name }}
</div>
</template>
<template #menu="{ record }">
<div>
<more-info :id="record.id" />
</div>
</template>
</a-table>
</div>
</div>
</div>
</template>
<route>
{
path: '/project/index',
}
</route>
<script>
import navbar from '@/components/navbar/index.vue'
import moreInfo from './components/more-info.vue'
import cityTree from '@/views/project/index/components/city-tree.vue'
import editProject from "@/views/project/index/components/edit.vue-project.vue";
export default {
components: {
cityTree,
navbar,
moreInfo,
editProject
},
data() {
return {
list: [],
name: '',
customerId: '',
page: {
page: 0,
size: 10,
total: 0
},
customerList: [],
years: [],
year: '',
city: null,
columns: [
{
title: '项目名称',
dataIndex: 'name'
},
{
title: '创建时间',
dataIndex: 'createdAt'
},
{
title: '创建人',
slotName: 'user'
},
{
title: '操作',
slotName: 'menu'
}
]
}
},
mounted() {
this.fetchList()
this.initYear()
},
methods: {
initYear() {
let year = new Date().getFullYear()
let startYear = 2021
for (let i = year; i >= startYear; i--) {
const item = { label: i.toString(), value: i }
this.years.push(item)
}
},
changeCustomer(e) {
this.city = e
this.customerId = e.id
this.fetchList()
},
pageChange(page) {
this.page.page = page - 1
this.fetchList()
},
fetchList() {
const data = {
name: this.name,
customerId: this.customerId,
year: this.year,
...this.page
}
this.$api.project.page(data).then(res => {
if (res.code === 200) {
this.list = res.data.records
this.page.total = res.data.total
}
})
}
}
}
</script>
<style lang="scss" scoped></style>

View File

@ -1,123 +0,0 @@
<template>
<div>
<navbar title="资料库" />
<div class="container flex flex-center flex-align-start">
<div
style="
flex: 1;
border-right: #f2f3f5 solid 1px;
padding: 0 16px;
"
>
<div class="font-14 bold flex-justify-start text-left">
<a-input placeholder="请输入项目名称">
<template #prefix>
<icon-search />
</template>
</a-input>
</div>
<a-divider />
<div>
<div v-for="(item, i) in 10" @click="index = i">
<div
class="text-left lines-1"
:class="index === item ? 'name_check' : 'name'"
>
项目名称项目名称项目名称项目名项目名称项目名称项目名称项目名
</div>
</div>
</div>
</div>
<div style="flex: 3">
<div style="padding: 0 16px">
<div class="flex flex-center flex-justify-between">
<div class="flex flex-center flex-justify-start ml-10">
<a-button-group>
<a-button>
<icon-left />
</a-button>
<a-button>
<icon-right />
</a-button>
</a-button-group>
<a-input
class="ml-10"
style="width: 380px"
placeholder="请输入名称搜索"
></a-input>
<a-button type="primary">搜索</a-button>
</div>
<div>
<a-button-group type="outline">
<a-button>新增</a-button>
<a-button>上传</a-button>
</a-button-group>
</div>
</div>
<a-divider />
<a-list
:bordered="false"
size="small"
:pagination-props="page"
>
<a-list-item v-for="item in 10">
<div>
<div
class="flex flex-center flex-justify-between"
>
<div class="flex flex-center">
<img
src="https://res.wutongshucloud.com/res/2024/12/04/202412041635423.svg"
style="width: 30px; height: 30px"
/>
<div>文件名称</div>
</div>
<div>332MB</div>
<div>修改日期</div>
<div>创建人</div>
</div>
</div>
</a-list-item>
</a-list>
</div>
</div>
</div>
</div>
</template>
<script>
import navbar from '@/components/navbar/index.vue'
export default {
components: {
navbar
},
data() {
return {
index: 1
}
}
}
</script>
<style lang="scss" scoped>
.name {
margin: 16px 1px;
border-radius: 4px;
padding: 4px;
}
.name_check {
border-radius: 4px;
margin: 10px 1px;
padding: 4px;
background-color: #eef2f9;
}
.name:hover {
border-radius: 4px;
margin: 10px 1px;
padding: 4px;
background-color: #eef2f9;
}
</style>

View File

@ -1,209 +0,0 @@
<template>
<div>
<a-button type="text" size="small" @click="show = true">更多</a-button>
<a-drawer
v-model:visible="show"
width="80%"
:header="false"
:footer="false"
>
<div v-if="task">
<div>{{ task.user.name }}创建于{{ task.createdAt }}</div>
<div class="flex flex-align-baseline">
<h2 >{{ task.name }}</h2>
<div class="mt-20">
<a-dropdown @select="changeStatus">
<a-button
type="primary"
size="small"
:style="
`background-color:` + task.status.remark.color
"
>{{ task.status.label }}
</a-button>
<template #content>
<a-doption
v-for="item in dict"
:key="item.id"
:value="item"
>{{ item.label }}
</a-doption>
</template>
</a-dropdown>
</div>
</div>
<a-divider />
<div class="flex flex-align-start flex-justify-between">
<div style="flex: 3">
<div>
<div
style="white-space: pre;min-height: 180px; border-radius: 8px"
class="grey-6-bg padding "
>
{{ task.remark }}
</div>
</div>
<div>
<a-tabs class="mt-10" @change="tabChange" :active-key="tabIndex">
<a-tab-pane title="相关文件" key="0"></a-tab-pane>
<a-tab-pane title="相关合同" key="1"></a-tab-pane>
</a-tabs>
</div>
<div v-if="tabIndex === 0">
<attach :project-id="task.projectId" :query-id="task.id" :type="1" folder="project_task_folder_init"/>
</div>
<div v-else-if="tabIndex === 1">
<contract :project-id="task.projectId" :task-id="task.id" />
</div>
</div>
<div style="flex: 1" class="ml-20">
<a-card>
<div class="font-18 bold">基础信息</div>
<a-divider />
<a-form auto-label-width>
<a-form-item label="优先级:">
<a-tag class="black bold" color="green"
>
</a-tag>
</a-form-item>
<a-form-item label="创建人:">
<div class="black bold">
{{ task.user.name }}
</div>
</a-form-item>
<a-form-item label="任务标签:">
<a-tag class="black bold" color="red">
{{ task.tag.label }}
</a-tag>
</a-form-item>
<a-form-item label="任务周期:">
<div class="black bold">
{{ task.startDate }} -
{{ task.endDate }}
</div>
</a-form-item>
<a-form-item label="执行人:">
<div
class="black bold flex flex-justify-start flex-wrap"
>
<div v-for="user in task.executors">
<a-tag class="mr-10" color="blue"
>{{ user.name }}
</a-tag>
</div>
</div>
</a-form-item>
</a-form>
</a-card>
</div>
</div>
</div>
</a-drawer>
</div>
</template>
<script>
import filePicker from '@/views/project/components/file-picker/index.vue'
import preview from '@/components/preview/index.vue'
import attach from "@/views/project/components/attach/index.vue";
import contract from "@/views/project/contract/index.vue"
export default {
components: {
filePicker,
preview,
attach,
contract
},
props: {
id: {
type: String,
default: ''
},
info:{
required:true,
type: Object,
default: null
}
},
watch: {
show: {
handler(val) {
if (val) {
if (this.info){
this.fetchDict()
this.task = this.info
console.log(this.task)
}
}
}
}
},
data() {
return {
show: false,
task: null,
fileList: [],
dict: [],
log: [],
tabIndex:0,
}
},
methods: {
tabChange(index){
console.log(index)
this.tabIndex = Number.parseInt(index )
},
fetchDict() {
this.$api.sys.dict({ code: 'project_task_status' }).then(res => {
if (res.code === 200) {
this.dict = res.data
this.fetchInfo()
}
})
},
changeStatus(res) {
this.task.status = res
const data = { id: this.task.id, status: this.task.status.value }
this.$api.task.submit(data).then(res => {
if (res.code === 200) {
this.$notification.success(res.msg)
}
})
},
success(files) {
this.fileList = this.fileList.concat(files)
this.fileList = Array.from(
new Map(this.fileList.map(item => [item.id, item])).values()
)
const data = {
id: this.task.id,
files: this.fileList.map(e => e.id).join(',')
}
this.$api.task.submit(data).then(res => {
if (res.code === 200) {
this.$notification.success(res.msg)
} else {
this.$notification.error(res.msg)
}
})
},
remove(file) {
const data = { id: this.task.id, fileId: file.id }
this.$api.task.removeFiles(data).then(res => {
if (res.code === 200) {
this.fileList = this.fileList.filter(
sub => sub.id !== file.id
)
this.$notification.success(res.msg)
} else {
this.$notification.error(res.msg)
}
})
},
}
}
</script>
<style lang="scss" scoped></style>

View File

@ -1,20 +0,0 @@
<template>
<div class="flex flex-center flex-col full-width full-height">
<img
src="https://res.wutongshucloud.com/res/2024/11/19/202411191459526.svg"
style="width: 400px"
/>
<div class="font-18 grey-6">当前账号无访问权限</div>
</div>
</template>
<route>
{
path: '/401',
}
</route>
<script>
export default {}
</script>
<style lang="scss" scoped></style>