Commit bee4864b authored by Zhang Xiaojie's avatar Zhang Xiaojie

团队二维码UI界面完成

parents c9906261 64dab1eb
import Mock from 'mockjs'
interface Contacts {
[key: string]: Array<Person>
}
interface Person {
id: string,
name: string,
isLeader: boolean,
isDirector: boolean
}
const contacts: Contacts = {
A: [],
B: [],
C: [],
D: [],
E: [],
F: [],
G: [],
H: [],
I: [],
J: [],
K: [],
L: [],
M: [],
N: [],
O: [],
P: [],
Q: [],
R: [],
S: [],
T: [],
U: [],
V: [],
W: [],
X: [],
Y: [],
Z: []
}
let hasLeader = false
let hasDirector = false
for (const key in contacts) {
const length = Mock.mock({
'number|1-5': 1
})
for (let i=0; i<=length.number; i++) {
const person: Person = {
id: key + i,
name: key + Mock.mock('@cname'),
isLeader: hasLeader ? false : Mock.mock({'boolean|1-2': true}).boolean,
isDirector: hasDirector ? false : Mock.mock({'boolean|1-2': true}).boolean,
}
hasLeader = hasLeader || person.isLeader
hasDirector = hasDirector ? hasDirector : person.isDirector
contacts[key].push(person)
}
}
export {
contacts,
Person
}
\ No newline at end of file
......@@ -15,7 +15,17 @@
// ]
// })
export const team = [{
import { contacts, Person } from './contacts'
interface Member {
parentId?: number,
parentName?: string,
id: number,
name: string,
children?: Array<Member>
}
const team = [{
id: 0,
name: '杭州复杂美科技有限公司',
children: [{
......@@ -50,4 +60,11 @@ export const team = [{
id: 3,
name: '运营部'
}]
}]
\ No newline at end of file
}]
export {
team,
contacts,
Person,
Member
}
\ No newline at end of file
......@@ -9,25 +9,51 @@ const routes: Array<RouteConfig> = [
path: '/',
name: 'Home',
component: App,
children:[
{
path: '/createteam',
name: 'createteam',
component: () => import('@/views/createteam.vue'),
meta:{
title:'创建团队'
}
}
]
redirect: '/team-management',
meta: {
title: '首页'
}
},
{
path: '/team-management',
name: 'Home',
component: () => import('@/views/team-management.vue'),
meta: {
title: '团队管理'
}
},
{
path: '/team',
path: '/team-frame',
name: 'Team',
component: () => import('@/views/team-frame.vue'),
meta: {
title: '团队架构'
}
},
{
path: '/team/:id',
name: 'TeamDetail',
component: () => import('@/views/team-detail.vue'),
meta: {
title: '团队架构'
}
},
{
path: '/team-create',
name: 'TeamCreate',
component: () => import('@/views/team-create.vue'),
meta:{
title:'创建团队'
}
},
{
path: '/team-QRcode',
name: 'TeamQRcode',
component: () => import('@/views/team-QRcode.vue'),
meta:{
title:'团队二维码'
}
}
]
const router = new VueRouter({
......
<template>
<button
class="py-2.5 text-center text-white w-full"
:class="getClass"
@click="clickButton"
>
<slot>按钮</slot>
</button>
</template>
<script lang="ts">
import Vue from 'vue'
export default Vue.extend({
components:{
// 'app-icon':()=>import('./components/common/Icon.vue'),
// 'main-page': () => import('@/layout/main-page.vue')
},
props: {
buttonBg: {
type: String,
default: 'bg-color-primary'
},
round: {
type: Boolean,
default: false
}
},
name: 'CButton',
computed: {
getClass() {
const className = this.round ? 'rounded-full' : 'rounded'
return `${className} ${this.buttonBg}`
}
},
methods: {
clickButton() {
this.$emit('click-button')
}
}
})
</script>
<style lang="less">
</style>
<template>
<div
class="mb-px flex text-text-primary items-center justify-between bg-white px-4 py-3 rounded"
@click="clickItem"
>
<div class="flex items-center justify-between flex-1 mr-1.5">
<div class="title">{{ title }}</div>
<div v-if="showContent" class="text-text-secondary">{{ content }}</div>
</div>
<app-icon
v-if="dot"
type="png"
:path="require('@/assets/icons/dot.png')"
class-name="h-5 w-1 ml-auto flex-shrink-0"
/>
</div>
</template>
<script lang="ts">
import Vue from 'vue'
export default Vue.extend({
components:{
'app-icon':()=>import('@/components/common/Icon.vue')
// 'main-page': () => import('@/layout/main-page.vue')
},
props: {
title: String,
dot: {
type: Boolean,
default: false
},
content: String
},
name: 'CCell',
computed: {
showContent() {
return this.content && this.content.replace(/(^\s*)|(\s*$)/g, '') !== ''
}
},
methods: {
clickItem() {
this.$emit('click-cell')
}
}
})
</script>
<style lang="less">
</style>
<template>
<!-- 通讯录成员 -->
<div class="flex items-center py-2">
<app-icon
type="png"
:path="require('@/assets/icons/avator.png')"
class-name="w-9 h-9"
/>
<div class="ml-3">{{ member.name }}</div>
<div
v-if="member.isDirector || member.isLeader"
class="tag ml-1.5 text-xs text-white px-1 py-0.5 bg-color-primary-lighter rounded"
>
{{ member.isLeader ? '负责人' : '主管'}}
</div>
</div>
</template>
<script lang="ts">
import Vue from 'vue'
export default Vue.extend({
components:{
'app-icon':()=>import('@/components/common/Icon.vue')
// 'main-page': () => import('@/layout/main-page.vue')
},
name: 'ContactMember',
props: {
member: {
type: Object,
default() {
return {}
}
}
}
})
</script>
<style lang="less">
</style>
<template>
<div class="team-contacts">
TeamContacts
<!-- 通讯录 -->
<div class="team-contacts relative">
<div class="nav-wrapper fixed top-1/2 transform -translate-y-1/2 right-0 w-6 z-20">
<div
v-for="(nav, index) in navs"
:key="index"
class="oy-0.5 text-center font-medium text-xs"
:class="currentNav === nav ? 'text-color-primary' : 'text-text-secondary'"
@click="clickNav(nav)"
>
{{ nav }}
</div>
</div>
<div class="leaders">
<div
v-for="(leader, index) in leaders"
:key="index"
class="flex items-center color-color-primary font-normal"
>
<contact-member :member="leader" />
</div>
</div>
<div class="members">
<div
v-for="(value, key) in contacts"
:key="key"
:ref="key"
>
<div class="text-text-secondary py-1 sticky top-12 bg-common-bg z-10">{{ key }}</div>
<div
v-for="(member, index) in contacts[key]"
:key="index"
>
<contact-member :member="member" />
</div>
</div>
</div>
</div>
</template>
<script lang="ts">
import Vue from 'vue'
import { Person } from '@/DTO/contacts'
export default Vue.extend({
props: {
contacts: {
type: Object,
default() {
return {}
}
}
},
components:{
// 'app-icon':()=>import('./components/common/Icon.vue'),
// 'main-page': () => import('@/layout/main-page.vue')
// 'app-icon':()=>import('@/components/common/Icon.vue'),
'contact-member': () => import('./contact-member.vue')
// 'contact-member-group': () => import('./contact-member-group.vue')
},
name: 'TeamContacts',
data() {
return {
currentNav: 'A',
scrollTop: 0
}
},
mounted() {
window.addEventListener('scroll', this.debounce(this.scrollHandler, 200))
},
beforeDestroy() {
window.removeEventListener('scroll', this.debounce(this.scrollHandler, 200))
},
computed: {
leaders() {
let arr: Array<Person> = []
for (const key in this.contacts) {
arr = arr.concat(this.contacts[key])
}
return arr.filter(item => item.isLeader || item.isDirector).sort((a, b) => Number(b.isLeader) - Number(a.isLeader))
},
navs() {
let arr: Array<string> = []
for (let key in this.contacts) {
arr.push(key)
}
return arr
}
},
name: 'TeamContacts'
methods: {
debounce(fn: ()=>void, delay: number) {
let timer: number | null
return function() {
if (timer !== null) {
clearTimeout(timer)
}
timer = setTimeout(() => {
fn()
}, delay)
}
},
scrollHandler() {
const top = document.documentElement.scrollTop
this.scrollTop = top
this.navs.forEach(nav => {
if ((this.$refs[nav] as Array<HTMLDivElement>).length > 0) {
const navTop = (this.$refs[nav] as Array<HTMLDivElement>)[0].getBoundingClientRect().top
if (navTop < 90) {
this.currentNav = nav
}
}
})
},
clickNav(nav: string) {
this.currentNav = nav
const div = (this.$refs[nav] as Array<HTMLDivElement>)[0]
const top = div.getBoundingClientRect().top
document.documentElement.scrollTop = this.scrollTop + top - 48
}
}
})
</script>
......
......@@ -16,9 +16,11 @@
<!-- 显示面包屑 -->
<div
v-else
class="bread"
class="bread py-3 flex items-center"
>
bread
<div class="pre text-text-secondary">{{ preTeam }}</div>
<div class="text-xs text-text-secondary px-2">></div>
<div class="pre text-text-primary font-medium">{{ member.name }}</div>
</div>
<!-- 子部门 -->
<div v-if="member.children && member.children.length > 0" class="children">
......@@ -58,14 +60,7 @@
<script lang="ts">
import Vue from 'vue'
export interface Member {
parentId?: number,
parentName?: string,
id: number,
name: string,
children?: Array<Member>
}
import { Member } from '@/DTO'
export default Vue.extend({
name: 'TeamTree',
......@@ -82,7 +77,8 @@ export default Vue.extend({
isDetail: {
type: Boolean,
default: false
}
},
preTeam: String
},
methods: {
clickChild(team: Member, parentName: string) {
......
<template>
<!-- 团队详情 -->
<main-page
left-arrow
@click-left="handleClickLeft"
>
<template slot="right">
<app-icon
type="png"
class-name="w-6.5 h-6.5"
:path="require('@/assets/icons/search.png')"
/>
</template>
<div class="px-4">
<!-- 团队架构详情 -->
<team-tree
isDetail
:tree-data="[currentTeam]"
:pre-team="parentTeam.name"
@click-child="clickItem"
/>
<!-- 通讯录 -->
<div class="pb-16">
<div class="text-text-secondary py-1">成员</div>
<team-contacts
:contacts="contacts"
/>
</div>
<!-- 底部操作 -->
<div class="py-2 px-4 grid grid-cols-3 gap-2.5 bg-common-bg w-screen fixed bottom-0 left-0 z-30">
<c-button @click-button="addMember">添加成员</c-button>
<c-button @click-button="addDepartment">添加部门</c-button>
<c-button @click-button="setDepartment">部门设置</c-button>
</div>
</div>
</main-page>
</template>
<script lang="ts">
import Vue from 'vue'
import { team, contacts } from '@/DTO'
import { Member } from '@/DTO'
export default Vue.extend({
name: 'TeamDetail',
components: {
'main-page': () => import('@/layout/main-page.vue'),
'app-icon': () => import('@/components/common/Icon.vue'),
'team-tree': () => import('@/views/components/team-tree.vue'),
'team-contacts': () => import('@/views/components/team-contacts.vue'),
'c-button': () => import('./components/c-button.vue')
},
// created() {
// },
data() {
let flatTeams: Array<Member> = []
let currentTeam: Member = {
id: 0,
name: ''
}
return {
title: '导航',
team,
contacts,
parentTeam: {},
currentTeam,
flatTeams,
// newTeams: []
}
},
methods: {
getFlatTeams(arr: Array<Member>) {
let newArr: Array<Member> = []
for (let i=0; i<arr.length; i++) {
newArr.push(arr[i])
if (arr[i].children?.length) {
newArr = newArr.concat(this.getFlatTeams(arr[i].children as Array<Member>))
}
}
return newArr
},
handleClickLeft() {
this.$router.go(-1)
},
clickItem(val: Member) {
console.log(val)
this.$router.push(`/team/${val.id}`)
},
addMember() {
console.log('添加成员')
},
addDepartment() {
console.log('添加部门')
},
setDepartment() {
console.log('设置部门')
}
},
watch: {
$route: {
handler() {
const id = parseInt(this.$route.params.id)
this.flatTeams = this.getFlatTeams(this.team)
this.currentTeam = this.flatTeams.find(team => team.id === id) as Member
const parentId = this.currentTeam.parentId
this.parentTeam = this.flatTeams.find(team => team.id === parentId) as Member
},
immediate: true
}
}
})
</script>
<style lang="less">
</style>
......@@ -12,12 +12,23 @@
/>
</template>
<div class="px-4">
<!-- 团队架构详情 -->
<team-tree
:tree-data="team"
@click-child="clickItem"
:tree-data="team"
@click-child="clickItem"
/>
<div class="border">
<team-contacts />
<!-- 通讯录 -->
<div class="pb-16">
<div class="text-text-secondary py-1">成员</div>
<team-contacts
:contacts="contacts"
/>
</div>
<!-- 底部操作 -->
<div class="py-2 px-4 grid grid-cols-3 gap-2.5 bg-common-bg w-screen fixed bottom-0 left-0 z-30">
<c-button round @click-button="addMember">添加成员</c-button>
<c-button round @click-button="addDepartment">添加部门</c-button>
<c-button round @click-button="setDepartment">部门设置</c-button>
</div>
</div>
</main-page>
......@@ -26,8 +37,8 @@
<script lang="ts">
import Vue from 'vue'
import { team } from '@/DTO'
import { Member } from './components/team-tree.vue'
import { team, contacts } from '@/DTO'
import { Member } from '@/DTO'
export default Vue.extend({
name: 'TeamFrame',
......@@ -35,7 +46,8 @@ export default Vue.extend({
'main-page': () => import('@/layout/main-page.vue'),
'app-icon': () => import('@/components/common/Icon.vue'),
'team-tree': () => import('@/views/components/team-tree.vue'),
'team-contacts': () => import('@/views/components/team-contacts.vue')
'team-contacts': () => import('@/views/components/team-contacts.vue'),
'c-button': () => import('./components/c-button.vue')
},
created() {
// console.log(Mock, 'mock')
......@@ -43,15 +55,27 @@ export default Vue.extend({
data() {
return {
title: '导航',
team
team,
contacts
}
},
methods: {
handleClickLeft() {
console.log('click left')
this.$router.go(-1)
},
clickItem(val: Member) {
console.log(val)
this.$router.push(`/team/${val.id}`)
},
addMember() {
console.log('添加成员')
},
addDepartment() {
console.log('添加部门')
},
setDepartment() {
console.log('设置部门')
}
}
})
......
<template>
<!-- 团队管理 -->
<main-page
left-arrow
@click-left="handleClickLeft"
>
<div class="px-4">
<!-- 头部 -->
<div class="flex items-start pt-1 pb-5">
<app-icon
type="png"
:path="require('@/assets/icons/team-icon.png')"
class-name="h-13 w-13"
/>
<!-- 名称 -->
<div class="ml-4 flex-1 text-text-primary">
<span>
这里是企业名称只有负责人可编辑修改修改
</span>
<app-icon
type="png"
:path="require('@/assets/icons/edit.png')"
class-name="h-3 w-3 inline-block ml-1"
/>
<!-- 团队号 -->
<div class="text-text-secondary text-sm font-medium mt-1.5">
团队号 ABCDE1234
</div>
</div>
</div>
<c-cell dot title="团队架构" @click-cell="$router.push('/team-frame')" />
<c-cell dot title="添加成员" />
<c-cell dot title="添加部门" />
<div class="mt-4">
<c-cell dot title="团队管理权限" content="共3人" />
<c-cell dot title="转让负责人" />
<c-cell dot title="申请管理" />
</div>
<c-button
round
buttonBg="bg-white"
class="text-text-primary mt-16"
>
解散团队
</c-button>
</div>
</main-page>
</template>
<script lang="ts">
import Vue from 'vue'
export default Vue.extend({
components:{
'app-icon':()=>import('@/components/common/Icon.vue'),
'main-page': () => import('@/layout/main-page.vue'),
'c-cell': () => import('./components/c-cell.vue'),
'c-button': () => import('./components/c-button.vue')
},
name: 'TeamManagement',
methods: {
handleClickLeft() {
console.log('click')
}
}
})
</script>
<style lang="less">
</style>
......@@ -9,11 +9,14 @@ module.exports = {
colors:{
'common-bg': '#F6F7F8',
'color-primary': '#32B2F7',
'color-primary-lighter': '#61C7FF',
'text-primary': '#24374E',
'text-secondary': '#8A97A5',
'border-lighter': '#E3EEF4'
},
spacing: {
6.5: '1.625rem',
13: '3.125rem',
}
},
screens: {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment