Commit c287605e authored by sixiaofeng's avatar sixiaofeng

客户信息/搜索页

parent 4e47b13e
import Mock, { Random } from 'mockjs'
enum Type {
Video = 'video',
Image = 'image'
}
interface Resource {
type: Type,
href: string
}
interface Records {
name: string,
time: string,
content: string,
resource?: Array<Resource>
}
const length = Mock.mock({
'number|1-10': 1
}).number
let records: Array<Records> = []
for (let i = 0; i <= length; i++) {
const obj: Records = {
name: Mock.mock('@cname'),
content: Mock.mock('@cparagraph(1, 4)'),
time: Mock.mock('@datetime("yyyy-MM-dd HH:mm:ss")')
}
const resource = Mock.mock({
'array|1-10': [
{
'type': 'image',
'href': Random.image('300x300', Mock.mock('@color'), '#FFF', 'png', 'image')
}
]
}).array
obj.resource = resource.length > 4 ? resource : []
records.push(obj)
}
// const xxx = Mock.mock({
// 'array|1-4': [
// {
// name: Mock.mock('@cname'),
// content: Mock.mock('@cparagraph(1, 4)'),
// time: Mock.mock('@datetime("yyyy-MM-dd HH:mm:ss")'),
// resource: Mock.mock({
// 'array|1-10': [
// {
// 'type': 'image',
// 'href': Random.image('200x100', Mock.mock('@color'), '#FFF', 'png', '!')
// }
// ]
// }).array
// }
// ]
// }).array
export {
Records,
Resource,
records
}
......@@ -53,7 +53,7 @@ import Vue from 'vue'
export default Vue.extend({
components:{
'app-icon':()=>import('@/components/common/Icon.vue')
// 'app-icon':()=>import('@/components/common/Icon.vue')
// 'main-page': () => import('@/layout/main-page.vue')
},
props: {
......
......@@ -7,6 +7,7 @@
/>
<form action=".">
<input
ref="c-search-input"
type="search"
class="py-2 rounded-full w-full pl-9"
:class="clearable ? 'pr-9' : 'pr-4'"
......@@ -18,7 +19,7 @@
<input type="text" style="display:none;"/>
</form>
<div
v-if="clearable && value.length > 0"
v-if="clearable && value && value.length > 0"
class="clear absolute right-0 top-1/2 transform -translate-y-1/2 px-3.5 py-3.5 flex items-center justify-center"
@click="clear"
>
......@@ -29,7 +30,7 @@
</div>
</div>
<div class="right flex-shrink-0 ml-4">
<slot name='right'>
<slot name='action'>
<div @click="$emit('cancel')">取消</div>
</slot>
</div>
......@@ -67,13 +68,17 @@ export default Vue.extend({
showError: false
}
},
mounted() {
(this.$refs['c-search-input'] as HTMLInputElement).focus()
},
methods: {
handleInput(e: InputEvent) {
this.$emit('input', (e.target as HTMLInputElement).value)
},
clear() {
console.log('xxx')
(this.$refs['c-search-input'] as HTMLInputElement).focus()
this.$emit('input', '')
},
keyPress(e: KeyboardEvent) {
if (e.key.toLowerCase() === 'enter') {
......
......@@ -3,6 +3,8 @@ import { RouteConfig } from 'vue-router'
/**
* 客户管理路由
* 客户管理 /client-management
* 客户信息 /client-info
* 搜索 /client-search
*/
export const clientRoutes: Array<RouteConfig> = [
......@@ -23,5 +25,13 @@ export const clientRoutes: Array<RouteConfig> = [
meta: {
title: '客户信息'
}
},
{
path: '/search-client',
component: () => import('@/views/client/search.vue')
},
{
path: '/search-result',
component: () => import('@/views/client/search-result.vue')
}
]
\ No newline at end of file
......@@ -4,22 +4,25 @@
header-bg="bg-color-primary"
title-color="text-white"
>
<template slot="left">
<app-icon
slot="left"
icon-name="left-arrow-white"
class-name="w-6.5 h-6.5"
@click="$router.go(-1)"
/>
</template>
<template slot="right">
<div class="h-6.5 w-6.5 flex items-center justify-end">
<div slot="right" class="h-6.5 w-6.5 flex items-center justify-end">
<app-icon
icon-name="dot-white"
class-name="w-1 h-5"
@click="$router.go(-1)"
@click="show = true"
/>
</div>
</template>
<van-action-sheet
v-model="show"
:actions="actions"
@select="onSelect"
/>
<!-- 头像名称 -->
<div class="content">
<div class="pt-14 header bg-color-primary px-4 pb-16">
<div class="info flex">
......@@ -34,7 +37,8 @@
</div>
</div>
</div>
<div class="px-4 -mt-11">
<!-- 信息 -->
<div class="px-4 -mt-11 pb-20">
<!-- 跟进 -->
<c-cell
dot
......@@ -42,8 +46,7 @@
title="跟进"
content="2"
>
<template slot="content">
<div class="w-full flex items-center mr-4 overflow-hidden">
<div slot="content" class="w-full flex items-center mr-4 overflow-hidden">
<app-icon
icon-name="avator"
class-name="h-6 w-6 mr-1"
......@@ -53,7 +56,6 @@
class-name="h-6 w-6"
/>
</div>
</template>
</c-cell>
<!-- 标签 -->
<c-cell
......@@ -61,8 +63,7 @@
title="标签"
content-align="items-start"
>
<template slot="content">
<div class="w-full flex flex-wrap items-center">
<div slot="content" class="w-full flex flex-wrap items-center">
<c-tag class="mr-1.5 mb-1.5" label="客户" />
<c-tag
class="mr-1.5 mb-1.5"
......@@ -88,7 +89,6 @@
text-color="text-tag-green"
/>
</div>
</template>
</c-cell>
<!-- 电话 -->
<c-cell
......@@ -96,8 +96,7 @@
title="电话"
content-align="items-start"
>
<template slot="content">
<div class="w-full flex">
<div slot="content" class="w-full flex">
<div class="flex-1">13112345678</div>
<div class="flex-shrink-0 grid grid-cols-2 gap-2.5">
<app-icon
......@@ -110,7 +109,6 @@
/>
</div>
</div>
</template>
</c-cell>
<!-- 邮箱 -->
<c-cell
......@@ -118,20 +116,84 @@
title="邮箱"
content-align="items-start"
>
<template slot="content">
<div class="w-full break-all">
<div slot="content" class="w-full break-all">
123456789@disanbo.com12
</div>
</template>
</c-cell>
<input-cell />
<!-- 地址 -->
<c-cell
title-color="text-text-secondary"
title="地址"
content-align="items-start"
>
<div slot="content" class="w-full break-all">
单行高度100,这里是输入的客户地址,没有地址不用显示
</div>
</c-cell>
<!-- 定位 -->
<c-cell dot>
<div slot="prefix" class="px-2">
<app-icon
icon-name="location"
class-name="w-4 h-4.5"
/>
</div>
<div slot="content" class="w-full text-text-secondary">
显示定位
</div>
</c-cell>
<!-- 公司 -->
<c-cell
title-color="text-text-secondary"
title="地址"
content-align="items-start"
>
<div slot="content" class="w-full break-all">
杭州复杂美科技有限公司
</div>
</c-cell>
<!-- 职位 -->
<c-cell
title-color="text-text-secondary"
title="职位"
content-align="items-start"
>
<div slot="content" class="w-full break-all">
市场经理
</div>
</c-cell>
<!-- 备注 -->
<c-cell
title-color="text-text-secondary"
title="备注"
content-align="items-start"
>
<div slot="content" class="w-full break-all">
这里是备注备注
</div>
</c-cell>
<!-- 跟进信息 -->
<div class="grid grid-cols-1 gap-y-4 mt-6">
<template v-for="(record, index) in records">
<follow-record
:key="index"
:record="record"
/>
</template>
</div>
</div>
</div>
<div class="fixed bottom-0 left-0 w-full px-4 py-2 bg-common-bg">
<c-button round>添加跟进记录</c-button>
</div>
</main-page>
</template>
<script lang="ts">
import Vue from 'vue'
import * as Records from '@/DTO/follow-records'
import { ActionSheet } from 'vant'
Vue.use(ActionSheet)
export default Vue.extend({
components:{
......@@ -139,12 +201,26 @@ export default Vue.extend({
'main-page': () => import('@/layout/main-page.vue'),
'c-cell': () => import('@/components/common/c-cell.vue'),
'c-tag': () => import('@/components/common/c-tag.vue'),
'input-cell': () => import('@/components/common/input-cell.vue'),
// 'client-card': () => import('@/views/client/components/client-card.vue')
'follow-record': () => import('@/views/client/components/follow-record.vue'),
'c-button': () => import('@/components/common/c-button.vue')
},
name: 'ClientManagement',
data() {
return {}
return {
records: Records.records,
show: false,
actions: [
{ name: '编辑', type: 'edit' },
{ name: '删除', type: 'delete'},
{ name: '退回公共资源', type: 'back'},
]
}
},
methods: {
onSelect(item: {name: string, type: string}) {
this.show = false
console.log(item.type, 'item')
}
}
})
</script>
......
......@@ -78,7 +78,9 @@ export default Vue.extend({
},
methods: {
clickTab(action: string) {
console.log(action)
if (action === 'search') {
this.$router.push('/search-client')
}
},
addClient() {
console.log('add client')
......
<template>
<div class="flex items-start">
<app-icon
icon-name="avator"
class-name="w-8 h-8 flex-shrink-0"
/>
<div class="info ml-1.5">
<div class="text-sm text-text-primary-dark">{{ record.name }}</div>
<div class="mt-1">{{ record.content }}</div>
<div v-if="record.resource.length > 0" class="mt-1.5 flex-1 grid grid-cols-4 gap-1">
<template v-if="record.resource.length > 4 && !showAll">
<div
v-for="(img, index) in preRecords"
:key="index"
class="rounded overflow-hidden"
@click="previewImages"
>
<img :src="img.href" alt="" class="max-w-full">
</div>
<div class="border flex items-center justify-center rounded bg-black bg-opacity-30 text-white" @click="showAll = true">
+{{ record.resource.length - 3 }}
</div>
</template>
<template v-else>
<div
v-for="(img, index) in record.resource"
:key="index"
class="rounded overflow-hidden"
@click="previewImages"
>
<img :src="img.href" alt="" class="max-w-full">
</div>
</template>
</div>
<div class="text-xs text-text-secondary mt-1">{{ record.time }}</div>
</div>
</div>
</template>
<script lang="ts">
import Vue from 'vue'
import { ImagePreview } from 'vant'
import * as Records from '@/DTO/follow-records'
Vue.use(ImagePreview)
export default Vue.extend({
name: "FollowRecord",
props: {
record: {
type: Object,
default() {
return {}
}
}
},
components: {
'app-icon':()=>import('@/components/common/Icon.vue'),
},
data() {
return {
showAll: false
}
},
computed: {
preRecords(): Array<Records.Records> {
if (this.record.resource.length > 4) {
return this.record.resource.slice(0, 3)
} else {
return this.record.resource
}
},
images() {
let arr: Array<string> = []
if (this.record.resource.length > 0) {
this.record.resource.forEach((item: Records.Resource) => {
arr.push(item.href)
})
}
return arr
}
},
methods: {
previewImages() {
ImagePreview({
images: this.images,
closeable: true
})
}
}
})
</script>
<style lang="less" scoped>
</style>
<template>
<!-- 搜索历史 -->
<div class="history mt-3">
<div class="text-sm text-text-secondary">搜索历史</div>
<template v-if="history.length > 0">
<div class="list mt-1">
<div
v-for="(item, index) in history"
:key="index"
class="flex items-center border-b border-border-lighter"
>
<app-icon
icon-name="history"
class-name="h-2.5 w-2.5 flex-shrink-0"
/>
<div class="pl-2.5 py-3.5 text-sm flex-1 truncate" @click="search(item)">{{ item }}</div>
<div class="h-11 w-11 flex items-center justify-end" @click="deleteHistory(item)">
<app-icon
icon-name="close-history"
class-name="h-5 w-5 flex-shrink-0"
/>
</div>
</div>
</div>
<div class="text-sm py-3.5 mt-1 text-center text-text-secondary" @click="clearHistory">
清空历史
</div>
</template>
<template v-else>
<div class="text-sm text-text-secondary text-center py-8">暂无搜索历史</div>
</template>
</div>
</template>
<script lang="ts">
import Vue from 'vue'
export default Vue.extend({
components:{
'app-icon':()=>import('@/components/common/Icon.vue')
},
name: 'SearchHistory',
props: {
history: {
type: Array,
default() {
return []
}
}
},
data() {
return {}
},
computed: {
historyCopy() {
return this.history
}
},
methods: {
deleteHistory(keyword: string) {
const index = this.historyCopy.findIndex(item => item === keyword)
this.historyCopy.splice(index, 1)
this.$emit('update:history', this.historyCopy)
},
clearHistory() {
this.historyCopy = []
this.$emit('update:history', this.historyCopy)
},
search(keyword: string) {
this.$emit('search', keyword)
}
}
})
</script>
<style lang="less">
</style>
......@@ -36,7 +36,7 @@ export default Vue.extend({
components:{
'app-icon':()=>import('@/components/common/Icon.vue'),
'main-page': () => import('@/layout/main-page.vue'),
'c-tag': () => import('@/components/common/c-tag.vue'),
// 'c-tag': () => import('@/components/common/c-tag.vue'),
'client-card': () => import('@/views/client/components/client-card.vue')
},
name: 'ClientManagement',
......
<template>
<!-- 搜索结果 -->
<main-page
left-arrow
@click-left="goBack"
>
<div slot="header" class="text-text-secondary flex items-center">
<div
class="py-1.5 px-4"
:class="currentKey === tab.key ? 'rounded-full bg-color-primary text-white' : ''"
v-for="tab in tabs"
:key="tab.key"
@click="currentKey = tab.key"
>
{{ tab.label }}
</div>
</div>
<div class="pt-12 px-4 pb-4">
<search-bar
v-model="search"
placeholder="客户姓名、公司名称"
class="sticky top-12"
@search="handleSearch"
>
<div
slot="action"
class="text-color-primary font-medium"
@click="$router.go(-1)"
>
取消
</div>
</search-bar>
<div class="mt-2">
<div class="result">
<div class="text-sm text-text-secondary py-1.5">客户姓名</div>
</div>
<div class="list">
<div
v-for="(client, index) in result.client"
:key="index"
class="flex items-center py-2">
<app-icon
icon-name="avator"
class-name="h-9 w-9"
/>
<div class="ml-2.5 flex-1 truncate">{{ client.name }}</div>
</div>
</div>
</div>
</div>
</main-page>
</template>
<script lang="ts">
import Vue from 'vue'
export default Vue.extend({
components:{
'search-bar':()=>import('@/components/common/search-bar.vue'),
'main-page': () => import('@/layout/main-page.vue'),
'app-icon': () => import('@/components/common/Icon.vue'),
'search-history': () => import('@/views/client/components/search-history.vue')
// 'client-card': () => import('@/views/client/components/client-card.vue')
},
name: 'SearchResult',
data() {
return {
tabs: [
{
label: '我跟进的',
key: 'mine'
},
{
label: '公共资源',
key: 'public'
}
],
currentKey: 'public',
result: {
client: [
{ name: '客户姓名' },
{ name: '刘强' },
{ name: '刘一只鱼' }
],
company: [
{ name: '刘大强信息咨询公司' },
{ name: '刘阿姨煎饼摊' }
]
},
search: ''
}
},
mounted() {
this.search = this.$route.query.keyword as string
},
methods: {
handleSearch() {
console.log(this.search, 'val')
},
goBack() {
this.$router.go(-1)
}
}
})
</script>
<style lang="less">
</style>
<template>
<!-- 搜索 -->
<main-page
left-arrow
@click-left="goBack"
>
<div slot="header" class="text-text-secondary flex items-center">
<div
class="py-1.5 px-4"
:class="currentKey === tab.key ? 'rounded-full bg-color-primary text-white' : ''"
v-for="tab in tabs"
:key="tab.key"
@click="currentKey = tab.key"
>
{{ tab.label }}
</div>
</div>
<div class="pt-12 px-4 pb-4">
<search-bar
v-model="search"
placeholder="客户姓名、公司名称"
class="sticky top-12"
@search="handleSearch"
>
<div
slot="action"
class="text-color-primary font-medium"
@click="$router.go(-1)"
>
取消
</div>
</search-bar>
<search-history
:history.sync="history"
@search="searchHistory"
/>
</div>
</main-page>
</template>
<script lang="ts">
import Vue from 'vue'
import Mock from 'mockjs'
const length = Mock.mock({
'number|1-10': 2
}).number
let history: Array<string> = []
for (let i=0; i<=length; i++) {
history.push(Mock.mock('@ctitle'))
}
export default Vue.extend({
components:{
'search-bar':()=>import('@/components/common/search-bar.vue'),
'main-page': () => import('@/layout/main-page.vue'),
'app-icon': () => import('@/components/common/Icon.vue'),
'search-history': () => import('@/views/client/components/search-history.vue')
// 'client-card': () => import('@/views/client/components/client-card.vue')
},
name: 'Search',
data() {
return {
history,
tabs: [
{
label: '我跟进的',
key: 'mine'
},
{
label: '公共资源',
key: 'public'
}
],
currentKey: 'public',
search: ''
}
},
methods: {
handleSearch() {
console.log(this.search, 'val')
this.$router.push({
path: '/search-result',
query: {
keyword: this.search
}
})
},
searchHistory(keyword: string) {
this.search = keyword
this.$router.push({
path: '/search-result',
query: {
keyword: this.search
}
})
},
goBack() {
this.$router.go(-1)
}
}
})
</script>
<style lang="less">
</style>
......@@ -11,6 +11,7 @@ module.exports = {
'color-primary': '#32B2F7',
'color-primary-lighter': '#61C7FF',
'text-primary': '#24374E',
'text-primary-dark': '#0D73AD',
'text-secondary': '#8A97A5',
'text-light': '#E6E6E6',
'border-lighter': '#E3EEF4',
......
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