agent-mine.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. <script setup lang="ts">
  2. import {
  3. getBroker,
  4. getDesignerStatistics,
  5. getFollowStatistics,
  6. getYearTarget,
  7. } from '../../../core/libs/requests'
  8. import { NetImages } from '../../../core/libs/net-images'
  9. import { useUserStore } from '../../../store'
  10. import { storeToRefs } from 'pinia'
  11. import qrCode from '@designer-hub/assets/src/libs/assets/qrCode'
  12. import Card from '@designer-hub/app/src/components/card.vue'
  13. import SectionHeading from '@designer-hub/app/src/components/section-heading.vue'
  14. import { getFollowUpPage, deleteFollowItem } from '@/core/libs/agent-requests'
  15. import { locationIcon } from '@designer-hub/assets/src/svgs'
  16. import { dayjs } from 'wot-design-uni'
  17. import PageHelperEvo from '@/components/page-helper-evo.vue'
  18. import ListHelperEvo from '@/components/list-helper-evo.vue'
  19. import { business } from '@/core/libs/svgs'
  20. const pageHelperRef = ref<ComponentExposed<typeof PageHelperEvo>>()
  21. const userStore = useUserStore()
  22. const { userInfo } = storeToRefs(userStore)
  23. const { data: agent, run: setAgent } = useRequest(() =>
  24. getBroker({ brokerId: String(userInfo.value.userId) }),
  25. )
  26. const { data: yearTarget, run: setYearTarget } = useRequest(() => getYearTarget())
  27. const { data: designerData, run: setDesignerData } = useRequest(() => getDesignerStatistics())
  28. const { data: followData, run: setFollowData } = useRequest(() => getFollowStatistics())
  29. const designerDataList = computed(() =>
  30. designerData.value
  31. ?.filter((it: any) => it.type !== 2)
  32. .map((it: any, index: number) => ({
  33. title: it.typeName,
  34. value: it.quantity ?? 0,
  35. subTitle: index === 0 ? designerData.value[1].typeName : '占比',
  36. subValue:
  37. index === 0
  38. ? designerData.value[1].quantity
  39. : `${((it.quantity / designerData.value[0].quantity) * 100).toFixed(0)}%`,
  40. })),
  41. )
  42. const bgClass = [
  43. 'bg-gradient-to-r from-[#fef3ee] to-[#f0f4f9]',
  44. 'bg-gradient-to-r from-[#fef8ee] to-[#f0f4f9]',
  45. 'bg-gradient-to-r from-[#eef4fe] to-[#f0f4f9]',
  46. 'bg-gradient-to-r from-[#faf2ff] to-[#f0f4f9]',
  47. ]
  48. const units = [
  49. // { },
  50. // 单位、 换算率
  51. // { unit: '万', rate: 1 },
  52. // { unit: '万', rate: 1 },
  53. // { unit: '次', rate: 1 },
  54. // { unit: '次', rate: 1 },
  55. { unit: '', rate: 1 },
  56. { unit: '', rate: 1 },
  57. { unit: '', rate: 1 },
  58. { unit: '', rate: 1 },
  59. ]
  60. const toSettings = () => {
  61. uni.navigateTo({ url: '/pages/mine/agent/settings/index' })
  62. }
  63. const toInvite = () => {
  64. uni.navigateTo({ url: '/pages/mine/agent/invite/index' })
  65. }
  66. const toBusinessCard = () => {
  67. uni.navigateTo({ url: '/pages/mine/agent/business-card/index' })
  68. }
  69. const confirmDelete = (id: number) => {
  70. uni.showModal({
  71. title: '提示',
  72. content: '是否确认删除该条跟进记录',
  73. success: async (success: any) => {
  74. if (!success.cancel) {
  75. const { code, msg, data } = await deleteFollowItem(id)
  76. console.log('点击了 确认删除', code, msg, data)
  77. if (code === 0) {
  78. await pageHelperRef.value?.refresh()
  79. }
  80. }
  81. },
  82. })
  83. }
  84. defineExpose({
  85. refresh: () => {
  86. setAgent()
  87. },
  88. })
  89. onMounted(async () => {
  90. await setAgent()
  91. await Promise.all([setYearTarget(), setDesignerData(), setFollowData()])
  92. uni.$on('refresh', async (val: any) => {
  93. await setFollowData()
  94. pageHelperRef.value?.refresh()
  95. })
  96. })
  97. </script>
  98. <template>
  99. <div>
  100. <div class="aspect-[0.96/1] absolute left-0 right-0 top--1">
  101. <wd-img
  102. width="100%"
  103. height="100%"
  104. :src="NetImages.AgentMineHeaderBg"
  105. custom-class="vertical-bottom"
  106. ></wd-img>
  107. </div>
  108. <!-- <wd-navbar
  109. fixed
  110. safeAreaInsetTop
  111. custom-class="bg-transparent!"
  112. :bordered="false"
  113. placeholder
  114. v-bind="navBarProps"
  115. ></wd-navbar> -->
  116. <div class="p-4 flex flex-col gap-4 relative">
  117. <div class="flex items-center px-4 mb-4" @click="toSettings">
  118. <wd-img
  119. round
  120. width="56"
  121. height="56"
  122. custom-class="border border-solid border-white"
  123. :src="agent?.headImgUrl"
  124. />
  125. <div class="mx-4 flex-1">
  126. <div class="text-white text-lg font-normal font-['PingFang_SC'] leading-normal">
  127. {{ agent?.brokerName }}
  128. </div>
  129. <!-- <div class="text-white text-xs font-normal font-['PingFang_SC'] leading-relaxed">-->
  130. <!-- ID:{{ agent?.inviteCode }}-->
  131. <!-- </div>-->
  132. </div>
  133. <!-- <div class="flex flex-col items-center mr-[30px]" @click.stop="toBusinessCard">
  134. <div class="w-[29px] h-[29px] relative">
  135. <wd-img width="28" height="28" :src="business"></wd-img>
  136. </div>
  137. <div class="text-white text-[10px] font-normal font-['PingFang_SC'] leading-relaxed">
  138. 个人名片
  139. </div>
  140. </div> -->
  141. <div class="flex flex-col items-center" @click.stop="toInvite">
  142. <div class="w-[29px] h-[29px] relative">
  143. <wd-img width="28" height="28" :src="qrCode"></wd-img>
  144. </div>
  145. <div class="text-white text-[10px] font-normal font-['PingFang_SC'] leading-relaxed">
  146. 邀请码
  147. </div>
  148. </div>
  149. </div>
  150. <Card>
  151. <SectionHeading title="本年目标" size="base"></SectionHeading>
  152. <div class="flex flex-col gap-2.5 mt-3">
  153. <template v-for="(it, i) in yearTarget" :key="i">
  154. <div class="rounded-lg flex items-center p-4 gap-6" :class="bgClass[i]">
  155. <div>
  156. <div class="w-[45px] h-[45px] rounded-full border-4 border-[#ffe2d0]">
  157. <div style="width: 50px; height: 50px">
  158. <wd-circle
  159. :model-value="
  160. it.thisYearComplete && it.target
  161. ? Number((Number(it.thisYearComplete) / Number(it.target)).toFixed(0)) *
  162. 100
  163. : 0
  164. "
  165. :size="50"
  166. :color="['#FF7742', '#FFAA42', '#4271FF', '#C131FF'][i]"
  167. :clockwise="false"
  168. >
  169. <div class="flex flex-col items-center">
  170. <div
  171. class="w-[29.20px] h-[18.39px] text-black text-sm font-medium font-['D-DIN-PRO']"
  172. >
  173. {{
  174. it.thisYearComplete && it.target
  175. ? ((Number(it.thisYearComplete) / Number(it.target)) * 100) % 1 === 0
  176. ? Number((Number(it.thisYearComplete) / Number(it.target)) * 100)
  177. : ((Number(it.thisYearComplete) / Number(it.target)) * 100).toFixed(
  178. 1,
  179. )
  180. : 0
  181. }}%
  182. </div>
  183. <div
  184. class="w-[22.71px] h-[10.82px] text-black/60 text-[7px] font-normal font-['PingFang_SC']"
  185. >
  186. 达成率
  187. </div>
  188. </div>
  189. </wd-circle>
  190. </div>
  191. </div>
  192. </div>
  193. <div class="flex-1">
  194. <div class="text-black/60 text-xs font-normal font-['PingFang_SC']">
  195. {{ it.typeName }}
  196. </div>
  197. <div class="flex items-center gap-1">
  198. <div class="text-black/90 text-lg font-medium font-['D-DIN-PRO'] leading-normal">
  199. <!-- 6000 -->
  200. <!-- {{ it.target / 10000 }}-->
  201. {{ it.target / units[i].rate }}
  202. </div>
  203. <div class="text-black text-xs font-normal font-['PingFang_SC']">
  204. {{ units[i].unit }}
  205. </div>
  206. </div>
  207. <div class="flex items-center gap-1">
  208. <div class="text-black/60 text-xs font-normal font-['PingFang_SC']">差值</div>
  209. <div class="text-[#ff2d2d] text-xs font-medium font-['D-DIN-PRO'] leading-normal">
  210. <!-- 3000 -->
  211. {{ (it.thisYearComplete ?? 0) - it.target / units[i].rate > 0 ? '+' : '' }}
  212. {{ (it.thisYearComplete ?? 0) - it.target / units[i].rate }}
  213. </div>
  214. <div
  215. class="text-[#ff2d2d] text-[10px] font-medium font-['D-DIN-PRO'] leading-normal"
  216. >
  217. {{ units[i].unit }}
  218. </div>
  219. </div>
  220. </div>
  221. <div class="">
  222. <div class="text-black/60 text-xs font-normal font-['PingFang_SC']">当年完成</div>
  223. <div class="flex items-center gap-1">
  224. <div class="text-black/90 text-lg font-medium font-['D-DIN-PRO'] leading-normal">
  225. <!-- 6000 -->
  226. {{ (it.thisYearComplete ?? 0) / units[i].rate }}
  227. </div>
  228. <div class="text-black text-xs font-normal font-['PingFang_SC']">
  229. {{ units[i].unit }}
  230. </div>
  231. </div>
  232. <div class="flex items-center gap-1">
  233. <div class="text-black/60 text-xs font-normal font-['PingFang_SC']">本月</div>
  234. <div class="text-[#0FC187] text-xs font-medium font-['D-DIN-PRO'] leading-normal">
  235. <!-- 3000 -->
  236. {{ (it.thisMonthComplete ?? 0) / units[i].rate }}
  237. </div>
  238. <div
  239. class="text-[#0FC187] text-[10px] font-medium font-['D-DIN-PRO'] leading-normal"
  240. >
  241. {{ units[i].unit }}
  242. </div>
  243. </div>
  244. </div>
  245. </div>
  246. </template>
  247. </div>
  248. </Card>
  249. <Card>
  250. <SectionHeading title="设计师数据" size="base"></SectionHeading>
  251. <div class="mt-3">
  252. <ListHelperEvo
  253. v-if="designerDataList?.length"
  254. :items="designerDataList"
  255. content-class="grid grid-cols-3 gap-2.5"
  256. >
  257. <template #default="{ item }">
  258. <div class="bg-[#f6f7ff] rounded-lg aspect-[1/1] flex flex-col justify-around p-2.5">
  259. <div class="text-black/60 text-xs font-normal font-['PingFang_SC'] leading-none">
  260. {{ item.title }}
  261. </div>
  262. <div class="text-black/90 text-lg font-bold font-['D-DIN_Exp'] leading-normal">
  263. {{ item.value }}
  264. </div>
  265. <div class="flex items-center gap-1">
  266. <div class="text-black/40 text-xs font-normal font-['PingFang_SC'] leading-none">
  267. {{ item.subTitle }}
  268. </div>
  269. <div class="text-[#ff2d2d] text-xs font-normal font-['D-DIN_Exp'] leading-normal">
  270. {{ item.subValue }}
  271. </div>
  272. </div>
  273. </div>
  274. </template>
  275. </ListHelperEvo>
  276. <!-- <template v-for="(it, i) in designerData" :key="i"></template>-->
  277. </div>
  278. </Card>
  279. <Card>
  280. <SectionHeading title="跟进数据" size="base"></SectionHeading>
  281. <div class="mt-3 grid grid-cols-3 gap-2.5">
  282. <template v-for="(it, i) in followData" :key="i">
  283. <div class="bg-[#f6f7ff] rounded-lg aspect-[1/1] flex flex-col justify-around p-2.5">
  284. <div class="text-black/60 text-xs font-normal font-['PingFang_SC'] leading-none">
  285. {{ it.typeName }}
  286. </div>
  287. <div class="text-black/90 text-lg font-bold font-['D-DIN_Exp'] leading-normal">
  288. {{ it.quantity ?? 0 }}
  289. </div>
  290. <div class="flex items-center gap-1">
  291. <div class="text-black/40 text-xs font-normal font-['PingFang_SC'] leading-none">
  292. 年新增
  293. </div>
  294. <div class="text-[#ff2d2d] text-xs font-normal font-['D-DIN_Exp'] leading-normal">
  295. {{ it.thisYearQuantity ?? 0 }}
  296. </div>
  297. </div>
  298. </div>
  299. </template>
  300. </div>
  301. </Card>
  302. <PageHelperEvo
  303. ref="pageHelperRef"
  304. :request="getFollowUpPage"
  305. :query="{ brokerId: userInfo.userId }"
  306. >
  307. <template #default="{ source }">
  308. <div class="flex flex-col gap-4">
  309. <template v-for="(it, index) in source?.list" :key="index">
  310. <div class="bg-white rounded-2xl shadow pl-[15px] py-[15px] flex-col gap-2 flex">
  311. <div class="flex items-center justify-between">
  312. <div
  313. class="text-black/90 text-base font-normal font-['PingFang_SC'] leading-relaxed"
  314. >
  315. {{ dayjs(it.followTime).format('YYYY-MM-DD HH:mm') }}
  316. </div>
  317. <div
  318. class="text-white text-xs font-normal font-['PingFang_SC'] leading-none pa-[8px]"
  319. :class="`${{ 1: 'bg-[#2357E9]', 2: 'bg-[#f8b344]' }[it.followType]}`"
  320. style="border-top-left-radius: 15px; border-bottom-left-radius: 5px"
  321. >
  322. <div class="flex items-center gap-1">
  323. <div class="w-1 h-1 bg-white rounded-full border"></div>
  324. <!-- 线下拜访 -->
  325. {{ it.followTypeName }}
  326. </div>
  327. </div>
  328. </div>
  329. <div
  330. class="text-black/60 text-sm font-normal font-['PingFang_SC'] leading-normal mr-[15px] mt-[29px]"
  331. >
  332. <!-- 和周老师在工作碰了环球项目,选了瓷砖款式,后天客户交定金,订单金额初步为
  333. 304958 -->
  334. {{ it.remark }}
  335. </div>
  336. <div class="mt-[15px] flex gap-2.5">
  337. <template v-for="(src, index) in it?.imgUrl?.split(',')" :key="index">
  338. <wd-img
  339. custom-class="rounded-lg overflow-hidden"
  340. width="70"
  341. height="70"
  342. :src="src"
  343. :enable-preview="true"
  344. />
  345. </template>
  346. </div>
  347. <div class="flex items-center justify-between mt-[19px] relative">
  348. <div
  349. class="h-[25px] px-1.5 bg-[#f4f4f4] rounded-md justify-center items-center gap-1 inline-flex"
  350. v-if="it?.followType == 1"
  351. >
  352. <wd-img width="15px" height="15px" :src="locationIcon"></wd-img>
  353. <div
  354. class="text-black/40 text-[10px] font-normal font-['PingFang_SC'] leading-[25px]"
  355. >
  356. <!-- 一间空间设计工作室 -->
  357. {{ it?.address.address }}
  358. </div>
  359. </div>
  360. <div
  361. class="text-black/90 text-sm font-normal font-['PingFang_SC'] leading-relaxed mr-[15px] absolute right-0"
  362. @click="confirmDelete(it.id)"
  363. >
  364. 删除
  365. <wd-icon name="close" size="14px"></wd-icon>
  366. </div>
  367. </div>
  368. </div>
  369. </template>
  370. </div>
  371. </template>
  372. </PageHelperEvo>
  373. </div>
  374. </div>
  375. </template>