123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616 |
- <route lang="json">
- {
- "style": {
- "navigationBarTitleText": "全部设计师",
- "navigationBarBackgroundColor": "#fff"
- }
- }
- </route>
- <script setup lang="ts">
- import Card from '@/components/card.vue'
- import DataForm from '@/components/data-form.vue'
- import PageHelperEvo from '@/components/page-helper-evo.vue'
- import { createFollowUp, focusOrCancel, getDesigners } from '../../../core/libs/agent-requests'
- import { filterIcon } from '@designer-hub/assets/src/svgs'
- import { Designer } from '@designer-hub/app/src/core/libs/models'
- import { requestToast } from '@designer-hub/app/src/core/utils/common'
- import { ComponentExposed } from 'vue-component-type-helpers'
- import { useFollowUp } from '../../../composables/followUp'
- import SectionHeading from '@designer-hub/app/src/components/section-heading.vue'
- import { useMemberLevelsStore } from '../../../store/member-levles'
- import { storeToRefs } from 'pinia'
- import { useUserStore } from '../../../store'
- import link from '@designer-hub/assets/src/libs/assets/link'
- import { beforeNow } from '@/utils/date-util'
- import { NetImages } from '@/core/libs/enums'
- import AMapWX from '@/pages/common/amap-wx.130'
- import { addUnit } from 'wot-design-uni/components/common/util'
- const action = ref(`${import.meta.env.VITE_SERVER_BASEURL}/app-api/infra/file/upload`)
- const userStore = useUserStore()
- const { userInfo } = storeToRefs(userStore)
- const searchText = ref('')
- const publishState = ref(false)
- const filterState = ref(false)
- const fileList = ref<string[]>([])
- const pageHelperRef = ref<ComponentExposed<typeof PageHelperEvo>>()
- const schemaTypeOnlineRef = ref<ComponentExposed<typeof DataForm>>()
- const { schema, rules, schemaTypeOnline } = useFollowUp()
- const memberLevelsStore = useMemberLevelsStore()
- const { memberLevels } = storeToRefs(memberLevelsStore)
- const { getMemberLevelLogo } = memberLevelsStore
- const followUpForm = ref({
- stylistId: '',
- followType: '1',
- followTime: new Date().getTime(),
- address: {
- latitude: 0,
- longitude: 0,
- address: '',
- },
- imgUrl: '',
- })
- const followUpFormRef = ref({})
- const currentAddress = ref<any>([])
- // 地图实例化
- const AmapFun = new AMapWX.AMapWX({ key: 'efde483f8801a09d3c5db032556e6593' })
- const wxGetAddress = (longitude: number, latitude: number) => {
- return new Promise((resolve, reject) => {
- AmapFun.getRegeo({
- location: `${longitude},${latitude}`,
- success: (res: any) => {
- resolve(res)
- },
- fail: (err: any) => {
- reject(err)
- },
- })
- })
- }
- const getCurrentLocation = () => {
- console.log('点击地址')
- uni.getLocation({
- type: 'gcj02',
- success: async (success: any) => {
- currentAddress.value = await wxGetAddress(success?.longitude, success?.latitude)
- const { name, latitude, longitude } = currentAddress.value[0]
- followUpForm.value.address.address = name
- followUpForm.value.address.latitude = latitude
- followUpForm.value.address.longitude = longitude
- console.log('提交信息:::', followUpForm.value)
- },
- fail: (err) => {
- console.log('获取地址失败', err)
- if (err.errCode === 1005 || err.errCode === 10001) {
- console.log('位置权限未授权')
- uni.authorize({
- scope: 'scope.userLocation',
- success: () => {
- uni.getLocation({
- type: 'gcj02',
- success: async (success) => {
- console.log('授权后,获取地址', success)
- currentAddress.value = await wxGetAddress(success?.longitude, success?.latitude)
- const { name, latitude, longitude } = currentAddress.value[0]
- followUpForm.value.address.address = name
- followUpForm.value.address.latitude = latitude
- followUpForm.value.address.longitude = longitude
- console.log('提交信息:::', followUpForm.value)
- },
- fail: function (err) {
- console.log('获取位置失败:', err)
- },
- })
- },
- fail: function () {
- console.log('用户拒绝授权,不再提示')
- // 用户拒绝授权,可以选择记录下来,不再提示
- uni.showToast({
- title: '您拒绝了位置授权',
- icon: 'none',
- duration: 2000,
- })
- // 可以引导用户去设置中授权
- uni.showModal({
- title: '提示',
- content: '请在系统设置中打开定位服务权限',
- success: function (modalRes) {
- if (modalRes.confirm) {
- uni.openSetting()
- }
- },
- })
- },
- })
- }
- },
- })
- }
- const filterQuery = ref<{
- tags: any[]
- levels: any[]
- retryStatus: any[]
- minPoints?: string
- maxPoints?: string
- brokerId?: string
- recommend?: boolean
- name?: string
- }>({
- tags: [],
- levels: [],
- retryStatus: [],
- brokerId: String(userInfo.value.userId),
- })
- const query = ref({})
- const searchFocus = async () => {
- console.log('focus')
- }
- const searchBlur = async () => {
- console.log('Blur')
- query.value = {
- ...filterQuery.value,
- tags: filterQuery.value.tags.join(','),
- levels: filterQuery.value.levels.join(','),
- }
- await pageHelperRef.value?.refresh()
- }
- const search = async () => {
- console.log('search')
- query.value = {
- ...filterQuery.value,
- tags: filterQuery.value.tags.join(','),
- levels: filterQuery.value.levels.join(','),
- }
- await pageHelperRef.value?.refresh()
- }
- const cancelSearch = () => {
- console.log('cancel')
- }
- const searchChange = (e: any) => {
- console.log(e)
- }
- const toDetail = async (designer: any) => {
- await uni.navigateTo({ url: '/pages/agent/designer/detail' + '?id=' + designer.id })
- }
- const callPhone = (phoneNumber: string) => {
- uni.makePhoneCall({
- phoneNumber,
- })
- }
- const filterData = () => {
- filterState.value = true
- }
- const handleImportant = async (designer: Designer) => {
- const { code } = await requestToast(
- () =>
- focusOrCancel({
- brokerId: Number(userInfo.value.userId),
- userId: Number(designer.id),
- }),
- {
- success: true,
- successTitle: '操作成功',
- },
- )
- if (code === 0) {
- await pageHelperRef.value?.refresh()
- }
- }
- const saveFollowUp = (item: any) => {
- console.log(item)
- schema.value.stylistId.props.columns = [{ value: item.id, label: item.name }]
- followUpForm.value.stylistId = item.id
- followUpForm.value.address.address = ''
- followUpForm.value.address.latitude = 0
- followUpForm.value.address.longitude = 0
- followUpForm.value.imgUrl = ''
- publishState.value = true
- }
- const createFollowUpSubmit = async () => {
- const { valid } = await followUpFormRef.value.validate()
- if (!valid) {
- return
- }
- if (fileList.value.length) {
- const temp: string[] = []
- fileList.value.forEach((each: any) => {
- temp.push(JSON.parse(each.response).data)
- })
- followUpForm.value.imgUrl = temp.join(',')
- }
- if (!followUpForm.value.imgUrl) {
- uni.showToast({ icon: 'none', title: '请上传图片' })
- return false
- }
- if (!followUpForm.value.address && followUpForm.value.followType === '1') {
- uni.showToast({ icon: 'none', title: '请刷新定位' })
- return false
- }
- const { code } = await requestToast(() => createFollowUp(followUpForm.value), {
- success: true,
- successTitle: '跟进成功',
- })
- if (code === 0) {
- publishState.value = false
- }
- }
- const handleChange = ({ fileList: files }) => {
- fileList.value = files
- console.log(fileList.value)
- }
- const handleSubmit = () => {
- query.value = {
- ...filterQuery.value,
- tags: filterQuery.value.tags ? filterQuery.value.tags.join(',') : '',
- levels: filterQuery.value.levels ? filterQuery.value.levels.join(',') : '',
- retryStatus: filterQuery.value.retryStatus ? filterQuery.value.retryStatus.join(',') : '',
- }
- filterState.value = false
- }
- const handleReset = () => {
- filterQuery.value = { tags: [], levels: [], brokerId: String(userInfo.value.userId) }
- query.value = {}
- }
- onLoad(async (params: { title?: string; filter?: string; tags?: string }) => {
- if (params.title) {
- uni.setNavigationBarTitle({ title: params.title })
- }
- if (params.filter) {
- const filter = JSON.parse(params.filter) as { tags: '' }
- }
- if (params.tags) {
- filterQuery.value.tags = params.tags.split(',')
- }
- query.value = {
- ...filterQuery.value,
- tags: filterQuery.value.tags.join(','),
- levels: filterQuery.value.levels.join(','),
- }
- })
- </script>
- <template>
- <view class="flex-grow">
- <PageHelperEvo ref="pageHelperRef" :request="getDesigners" :query="query">
- <template #top>
- <div class="flex items-center justify-between bg-white pr-3.5">
- <div class="flex-1">
- <wd-search
- v-model="filterQuery.name"
- placeholder="输入设计师姓名模糊搜索"
- @focus="searchFocus"
- @blur="searchBlur"
- @search="search"
- @cancel="cancelSearch"
- @change="searchChange"
- hide-cancel
- />
- </div>
- <wd-img :src="filterIcon" width="22px" height="22px" @click="filterData"></wd-img>
- </div>
- </template>
- <template #default="{ source }">
- <div class="p-3.5 gap-3.5 flex flex-col">
- <template v-for="(it, i) in source?.list" :key="i">
- <Card>
- <div class="items-center" @click="toDetail(it)">
- <div class="">
- <div class="flex items-center">
- <div
- class="w-[55px] h-[55px] bg-neutral-100 rounded-full mr-2 flex items-center justify-center relative"
- >
- <wd-img
- width="100%"
- height="100%"
- round
- :src="it.avatar || NetImages.DefaultAvatar"
- ></wd-img>
- <div v-if="it.retryStatus === 1" class="absolute right-0 bottom--1">
- <wd-img width="14" height="14" :src="link"></wd-img>
- </div>
- </div>
- <div class="flex flex-col flex-1">
- <div class="flex-row flex items-center justify-between w-full">
- <div class="flex-row flex items-center">
- <div class="text-black/90 text-base font-normal font-['PingFang_SC']">
- <!-- 苏小萌 -->
- {{ it.name }}
- </div>
- <div
- class="h-4 rounded-[20px] justify-start items-center inline-flex flex-row ml-[9px]"
- >
- <div
- v-if="it.recommend"
- class="text-[10px] bg-[#fff3e4] px-[4px] py-[4px] c-[#f2a64f] rounded-[3px]"
- >
- 推荐设计师
- </div>
- <wd-img
- v-if="it.levelId"
- width="63"
- height="18.6"
- custom-class="ml-[9px]"
- :src="getMemberLevelLogo(Number(it.levelId))"
- ></wd-img>
- </div>
- </div>
- <!-- <div-->
- <!-- class="text-black/60 text-xs font-normal font-['PingFang_SC'] leading-snug flex items-center"-->
- <!-- @click.stop="toHomePage(it.id)"-->
- <!-- >-->
- <!-- <div>个人主页</div>-->
- <!-- <wd-img width="13" height="13" :src="rightArrowIcon"></wd-img>-->
- <!-- </div>-->
- </div>
- <div class="flex items-center gap-2 mt-[18px]">
- <div
- class="text-black/30 text-xs font-normal font-['PingFang_SC'] leading-none"
- >
- {{ it.accessTime ? `${beforeNow(new Date(it.accessTime))}跟进` : '' }}
- </div>
- <div class="bg-[#eeeeee] w-[2px] h-[10px]"></div>
- <div
- class="text-black/30 text-xs font-normal font-['PingFang_SC'] leading-none"
- >
- 积分:{{ it.points || 0 }}
- </div>
- </div>
- </div>
- </div>
- </div>
- <div class="row-start-2 col-start-2 col-end-4">
- <div
- class="flex items-center w-full mt-[20px]"
- style="justify-content: flex-start"
- >
- <div v-if="!it.followUp30Days" class="flex items-center justify-center w-[30%]">
- <div class="w-2 h-2 bg-[#89f4e2] rounded-full mr-[7px]"></div>
- <div
- class="text-black/90 text-xs font-normal font-['PingFang_SC'] leading-snug"
- >
- 30天未跟进
- </div>
- </div>
- <div
- class="flex items-center justify-center w-[35%]"
- v-if="!it.generatePoints60Days"
- >
- <div class="w-2 h-2 bg-[#ffb96a] rounded-full mr-[7px]"></div>
- <div
- class="text-black/90 text-xs font-normal font-['PingFang_SC'] leading-snug"
- >
- 60天未产生积分
- </div>
- </div>
- <div
- class="flex items-center justify-center w-[35%]"
- v-if="!it.expendPoints60Days"
- >
- <div class="w-2 h-2 bg-[#c493ff] rounded-full mr-[7px]"></div>
- <div
- class="text-black/90 text-xs font-normal font-['PingFang_SC'] leading-snug"
- >
- 60天未消耗积分
- </div>
- </div>
- </div>
- </div>
- <div
- class="row-start-5 col-start-2 col-end-4 flex items-center mt-[26px] justify-around"
- >
- <div
- v-if="!it.focus"
- class="px-3 py-1.5 rounded-[30px] border border-solid border-[#ff2d2d] justify-center items-center gap-1 flex"
- @click.stop="handleImportant(it)"
- >
- <!-- <span style="color: #ff2d2d" class="flex items-center">+</span> -->
- <wd-icon name="add" color="#ff2d2d" size="10"></wd-icon>
- <div
- class="text-[#ff2d2d] text-xs font-normal font-['PingFang_SC'] leading-none"
- >
- 重点跟进
- </div>
- </div>
- <div
- v-else
- class="px-3 py-1.5 rounded-[30px] border border-solid border-[#dcdcdc] justify-center items-center gap-1 inline-flex"
- @click.stop="handleImportant(it)"
- >
- <!-- 对号图标 -->
- <wd-icon name="check-bold" color="#8b8b8b" size="14"></wd-icon>
- <div
- class="text-[#8b8b8b] text-xs font-normal font-['PingFang_SC'] leading-none"
- >
- 已重点跟进
- </div>
- </div>
- <div
- class="px-5 py-1 bg-[#e1ecff] rounded-[30px] border border-[#2357e9] justify-center items-center gap-1 inline-flex"
- @click.stop="callPhone(it.mobile)"
- >
- <div
- class="text-center text-[#2357e9] text-sm font-normal font-['PingFang_SC'] leading-normal"
- >
- 打电话
- </div>
- </div>
- <div
- class="px-5 py-1 bg-[#0052d9] rounded-[30px] justify-center items-center gap-1 inline-flex"
- >
- <div
- class="text-center text-white text-sm font-normal font-['PingFang_SC'] leading-normal"
- @click.stop="saveFollowUp(it)"
- >
- 写跟进
- </div>
- </div>
- </div>
- </div>
- </Card>
- </template>
- </div>
- </template>
- </PageHelperEvo>
- </view>
- <wd-action-sheet v-model="publishState" title="创建跟进" @close="publishState = false">
- <view class="flex flex-col p-4 overflow-y-auto h-[calc(75vh)]">
- <div>
- <DataForm
- ref="followUpFormRef"
- :schema="schema"
- v-model="followUpForm"
- :rules="rules"
- direction="horizontal"
- ></DataForm>
- <!-- 根据 followType 值 区分 线下 线上 -->
- <template v-if="followUpForm.followType === '1'">
- <div
- class="grid mb-4 items-start"
- :style="{ 'grid-template-columns': `${addUnit(64)} auto` }"
- >
- <label class="text-sm font-normal leading-relaxed text-black/60 h-10 flex items-center">
- <span
- class="text-[#ef4343] text-base font-normal font-['PingFang_SC'] leading-normal visible"
- >
- *
- </span>
- 地址
- </label>
- <div class="wd-input h-[40px] lh-[40px] flex justify-between px-[20px]">
- <div>
- {{
- !followUpForm.address.address ? '点击获取当前位置' : followUpForm.address.address
- }}
- </div>
- <wd-icon name="refresh" size="14px" @click="getCurrentLocation"></wd-icon>
- </div>
- </div>
- </template>
- <div
- class="grid mb-4 items-start"
- :style="{ 'grid-template-columns': `${addUnit(64)} auto` }"
- >
- <label class="text-sm font-normal leading-relaxed text-black/60 h-10 flex items-center">
- <span
- class="text-[#ef4343] text-base font-normal font-['PingFang_SC'] leading-normal visible"
- >
- *
- </span>
- 图片
- </label>
- <wd-upload
- :file-list="fileList"
- image-mode="aspectFill"
- accept="media"
- :action="action"
- :multiple="true"
- :limit="9"
- @change="handleChange"
- ></wd-upload>
- </div>
- </div>
- <div><wd-button block :round="false" @click="createFollowUpSubmit">提交</wd-button></div>
- </view>
- </wd-action-sheet>
- <!-- 筛选action-sheet -->
- <wd-action-sheet v-model="filterState" title="筛选" @close="filterState = false">
- <view class="flex flex-col p-4 overflow-y-auto h-[calc(75vh)]">
- <SectionHeading title="标签"></SectionHeading>
- <wd-checkbox-group shape="button" v-model="filterQuery.tags">
- <template
- v-for="(tag, index) in [
- // { label: '全部', value: '' },
- { label: '重点跟进', value: '1' },
- { label: '本月新增', value: '2' },
- { label: '超过30天未跟进', value: '3' },
- { label: '超过60天未产生积分', value: '4' },
- { label: '超过60天未消耗积分', value: '5' },
- { label: '未成交过', value: '6' },
- ]"
- :key="index"
- >
- <wd-checkbox custom-class="w-50%!" :model-value="tag.value">
- {{ tag.label }}
- </wd-checkbox>
- </template>
- </wd-checkbox-group>
- <SectionHeading title="会员等级"></SectionHeading>
- <wd-checkbox-group shape="button" v-model="filterQuery.levels">
- <template
- v-for="(tag, index) in memberLevels.map((it) => ({
- label: it.memberLevelName,
- value: it.id,
- }))"
- :key="index"
- >
- <wd-checkbox custom-class="w-50%!" :model-value="tag.value">{{ tag.label }}</wd-checkbox>
- </template>
- </wd-checkbox-group>
- <SectionHeading title="积分区间"></SectionHeading>
- <div class="flex items-center justify-between py-4">
- <wd-input
- v-model="filterQuery.minPoints"
- custom-class="h-10 bg-[#f5f7f9]!"
- no-border
- ></wd-input>
- <div class="w-4 h-.25 bg-black/35"></div>
- <wd-input
- v-model="filterQuery.maxPoints"
- custom-class="h-10 bg-[#f5f7f9]!"
- no-border
- ></wd-input>
- </div>
- <SectionHeading title="绑定关系"></SectionHeading>
- <wd-checkbox-group shape="button" v-model="filterQuery.retryStatus">
- <template
- v-for="(tag, index) in [
- // { label: '全部', value: '' },
- { label: '弱绑定', value: '0' },
- { label: '强绑定', value: '1' },
- ]"
- :key="index"
- >
- <wd-checkbox custom-class="w-50%!" :model-value="tag.value">
- {{ tag.label }}
- </wd-checkbox>
- </template>
- </wd-checkbox-group>
- <SectionHeading title="推荐设计师"></SectionHeading>
- <wd-checkbox-group shape="button" v-model="filterQuery.recommend">
- <template
- v-for="(tag, index) in [
- // { label: '全部', value: '' },
- { label: '否', value: false },
- { label: '是', value: true },
- ]"
- :key="index"
- >
- <wd-checkbox custom-class="w-50%!" :model-value="tag.value">
- {{ tag.label }}
- </wd-checkbox>
- </template>
- </wd-checkbox-group>
- <div class="flex gap-4 pt-[10px]">
- <div class="flex-1">
- <wd-button block :round="false" @click="handleReset">重置</wd-button>
- </div>
- <div class="flex-1">
- <wd-button block :round="false" @click="handleSubmit">提交</wd-button>
- </div>
- </div>
- </view>
- </wd-action-sheet>
- </template>
- <style scoped lang="scss">
- .filter-item {
- @apply w-[168px] h-10 bg-[#f5f7f9] rounded-lg flex items-center justify-center;
- &-text {
- @apply text-black/90 text-sm font-normal font-['PingFang_SC'] leading-none;
- }
- }
- </style>
|