| @@ -27,8 +27,6 @@ declare module 'vue' { | |||||
| NutEmpty: typeof import('@nutui/nutui-taro')['Empty'] | NutEmpty: typeof import('@nutui/nutui-taro')['Empty'] | ||||
| NutForm: typeof import('@nutui/nutui-taro')['Form'] | NutForm: typeof import('@nutui/nutui-taro')['Form'] | ||||
| NutFormItem: typeof import('@nutui/nutui-taro')['FormItem'] | NutFormItem: typeof import('@nutui/nutui-taro')['FormItem'] | ||||
| NutGrid: typeof import('@nutui/nutui-taro')['Grid'] | |||||
| NutGridItem: typeof import('@nutui/nutui-taro')['GridItem'] | |||||
| NutInput: typeof import('@nutui/nutui-taro')['Input'] | NutInput: typeof import('@nutui/nutui-taro')['Input'] | ||||
| NutNavbar: typeof import('@nutui/nutui-taro')['Navbar'] | NutNavbar: typeof import('@nutui/nutui-taro')['Navbar'] | ||||
| NutRow: typeof import('@nutui/nutui-taro')['Row'] | NutRow: typeof import('@nutui/nutui-taro')['Row'] | ||||
| @@ -4,7 +4,7 @@ export default defineAppConfig({ | |||||
| 'pages/contact/index', | 'pages/contact/index', | ||||
| 'pages/contact-new/index', | 'pages/contact-new/index', | ||||
| 'pages/contact-edit/index', | 'pages/contact-edit/index', | ||||
| 'pages/invite/index', | |||||
| 'pages/notifications/index', | |||||
| 'pages/settings/index', | 'pages/settings/index', | ||||
| 'pages/login/index', | 'pages/login/index', | ||||
| 'pages/web-view/index', | 'pages/web-view/index', | ||||
| @@ -25,16 +25,16 @@ export default defineAppConfig({ | |||||
| list: [ | list: [ | ||||
| { | { | ||||
| pagePath: 'pages/index/index', | pagePath: 'pages/index/index', | ||||
| selectedIconPath: 'images/bell-solid-397ef5.png', | |||||
| iconPath: 'images/bell-regular-797979.png', | |||||
| text: '通知' | |||||
| }, | |||||
| { | |||||
| pagePath: 'pages/invite/index', | |||||
| selectedIconPath: 'images/calendar-plus-solid-397ef5.png', | selectedIconPath: 'images/calendar-plus-solid-397ef5.png', | ||||
| iconPath: 'images/calendar-plus-regular-797979.png', | iconPath: 'images/calendar-plus-regular-797979.png', | ||||
| text: '邀约' | text: '邀约' | ||||
| }, | }, | ||||
| { | |||||
| pagePath: 'pages/notifications/index', | |||||
| selectedIconPath: 'images/bell-solid-397ef5.png', | |||||
| iconPath: 'images/bell-regular-797979.png', | |||||
| text: '通知' | |||||
| }, | |||||
| { | { | ||||
| pagePath: 'pages/contact/index', | pagePath: 'pages/contact/index', | ||||
| selectedIconPath: 'images/address-book-solid-397ef5.png', | selectedIconPath: 'images/address-book-solid-397ef5.png', | ||||
| @@ -1,6 +1,6 @@ | |||||
| export default definePageConfig({ | export default definePageConfig({ | ||||
| navigationBarTitleText: '', | navigationBarTitleText: '', | ||||
| navigationStyle: 'custom', | |||||
| disableScroll: true, | |||||
| usingComponents: {}, | usingComponents: {}, | ||||
| navigationStyle: 'custom', | |||||
| disableScroll: true | |||||
| }) | }) | ||||
| @@ -11,8 +11,20 @@ page { | |||||
| overflow: scroll; | overflow: scroll; | ||||
| } | } | ||||
| .skeleton { | |||||
| flex: 1; | |||||
| overflow: hidden; | |||||
| .nut-grid-item__content { | |||||
| padding: 0; | |||||
| display:unset; | |||||
| } | |||||
| .nut-grid-item__content--border { | |||||
| border-right-width: unset; | |||||
| border-bottom-width: unset; | |||||
| } | |||||
| .nut-grid-item__content--surround { | |||||
| border-top-width: unset; | |||||
| border-left-width: unset; | |||||
| } | } | ||||
| .skeleton-avatar .nut-skeleton-content__line { | |||||
| visibility: hidden !important; | |||||
| display: none !important; | |||||
| } | |||||
| @@ -1,176 +1,208 @@ | |||||
| <script setup lang="ts"> | |||||
| import { reactive } from 'vue' | |||||
| import { View } from '@tarojs/components' | |||||
| <script lang="ts" setup> | |||||
| import Contact from "../../components/contact" | |||||
| import { Router } from 'tarojs-router-next' | |||||
| import {reactive, ref} from 'vue'; | |||||
| import './index.scss' | import './index.scss' | ||||
| import {weappAuth} from "../../utils"; | |||||
| import {GroupedPassRecords, usePassRecordsStore} from "../../stores/pass-records"; | |||||
| import {useContactsStore} from "../../stores/contacts"; | |||||
| import { useContactsStore, ContactData } from '../../stores/contacts' | |||||
| import { registerRouterBackListener } from 'tarojs-router-next' | |||||
| import {BjxHelper} from "../../utils"; | |||||
| import {gql} from "graphql-tag"; | |||||
| import {PinyinHelper, GQLRequest, weappAuth} from "../../utils"; | |||||
| import {useAuthStore} from "../../stores/auth"; | |||||
| // defineExpose({ | |||||
| // loadContactsFromServer, | |||||
| // }); | |||||
| const state = reactive<{ | const state = reactive<{ | ||||
| isPageDataLoading: boolean, | |||||
| isAuthError: boolean, | isAuthError: boolean, | ||||
| groupedPassRecords: GroupedPassRecords[], | |||||
| isContactDataLoadError: boolean, | |||||
| isContactDataLoading: boolean, | |||||
| searchQuery: string, | |||||
| normalContacts: ContactData[], | |||||
| flexContacts: ContactData[], // Generic type for now | |||||
| }>({ | }>({ | ||||
| isPageDataLoading: true, | |||||
| isAuthError: false, | isAuthError: false, | ||||
| groupedPassRecords: [], | |||||
| isContactDataLoadError: false, | |||||
| isContactDataLoading: true, | |||||
| searchQuery: "", | |||||
| normalContacts: [], | |||||
| flexContacts: [] | |||||
| }) | }) | ||||
| const passRecords = usePassRecordsStore() | |||||
| const contacts = useContactsStore() | const contacts = useContactsStore() | ||||
| init() | init() | ||||
| function init() { | function init() { | ||||
| state.isAuthError = false | state.isAuthError = false | ||||
| state.isPageDataLoading = true | |||||
| weappAuth().then(r => { | |||||
| console.log(r) | |||||
| passRecords.loadPassRecordsFromServer().then( passRecords => { | |||||
| state.groupedPassRecords = passRecords | |||||
| console.log("aaa",state.groupedPassRecords ) | |||||
| // console.log(state.groupedPassRecords) | |||||
| contacts.loadContactsFromServer().then( contacts => { | |||||
| state.isPageDataLoading = false | |||||
| state.isContactDataLoadError = false | |||||
| state.isContactDataLoading = true | |||||
| weappAuth() | |||||
| .then(r => { | |||||
| contacts.loadContactsFromServer().then( | |||||
| contactList => { | |||||
| console.log("contactList", contactList) | |||||
| generateContactGroupList(contactList) | |||||
| state.isContactDataLoading = false | |||||
| }) | |||||
| .catch(e => { | |||||
| state.isAuthError = false | |||||
| state.isContactDataLoadError = true | |||||
| state.isContactDataLoading = false | |||||
| }) | |||||
| }) | }) | ||||
| .catch(contactError => { | |||||
| console.log("error", contactError) | |||||
| .catch(e=> { | |||||
| console.log("error", e) | |||||
| state.isAuthError = true | state.isAuthError = true | ||||
| state.isPageDataLoading = false | |||||
| state.isContactDataLoadError = false | |||||
| state.isContactDataLoading = false | |||||
| }) | }) | ||||
| }) | |||||
| .catch(error => { | |||||
| console.log("error", error) | |||||
| state.isAuthError = true | |||||
| state.isPageDataLoading = false | |||||
| }) | |||||
| }).catch(e => { | |||||
| console.log("error", e) | |||||
| state.isAuthError = true | |||||
| state.isPageDataLoading = false | |||||
| registerRouterBackListener((to, from) => { | |||||
| if ((from.url === "/pages/contact-new/notifications" && to.url === "/pages/index/notifications") | |||||
| || (from.url === "/pages/contact-edit/notifications" && to.url === "/pages/index/notifications") | |||||
| ) { | |||||
| generateContactGroupList(contacts.allContacts) | |||||
| } | |||||
| }) | }) | ||||
| } | } | ||||
| const onAuthErrorRefresh = () => { | const onAuthErrorRefresh = () => { | ||||
| init() | init() | ||||
| } | } | ||||
| // const onPullDownRefresh = () => { | |||||
| // console.log("onPullDownRefresh") | |||||
| // state.isRefresherTriggered = false | |||||
| // } | |||||
| function onPullDownRefresh (e) { | |||||
| console.log("onPullDownRefresh", e) | |||||
| // state.isRefresherTriggered = false | |||||
| const onContactDataLoadErrorRefresh = () => { | |||||
| state.isContactDataLoadError = false | |||||
| state.isContactDataLoading = true | |||||
| contacts.loadContactsFromServer().then( | |||||
| contactList => { | |||||
| console.log("contactList", contactList) | |||||
| generateContactGroupList(contactList) | |||||
| state.isContactDataLoading = false | |||||
| }) | |||||
| .catch(e => { | |||||
| state.isContactDataLoadError = true | |||||
| state.isContactDataLoading = false | |||||
| }) | |||||
| } | } | ||||
| // | |||||
| // | |||||
| // const show = ref(false); | |||||
| // | |||||
| // const state = reactive({ | |||||
| // msg: '欢迎使用 NutUI4.0 开发小程序', | |||||
| // msg2: '你成功了~', | |||||
| // isVisible1: false, | |||||
| // val: '' | |||||
| // }) | |||||
| // | |||||
| // const handleClick = msg => { | |||||
| // state.msg = msg | |||||
| // } | |||||
| // | |||||
| // useDidShow(() => { | |||||
| // console.log("did show is run xxxxxxx.") | |||||
| // }) | |||||
| // | |||||
| // useLoad(() => { | |||||
| // console.log("use load is run xxxxxxx.") | |||||
| // }) | |||||
| const generateContactGroupList = (contactList: ContactData[]) => { | |||||
| state.normalContacts = [] | |||||
| state.flexContacts = [] | |||||
| for (const item of contactList) { | |||||
| if (item.flexVisit === true) state.flexContacts.push(item) | |||||
| else state.normalContacts.push(item) | |||||
| } | |||||
| } | |||||
| const goToContactNewPage = () => { | |||||
| Router.toContactNew() | |||||
| } | |||||
| const goToContactEditPage = (item) => { | |||||
| Router.toContactEdit({ data: item }) | |||||
| } | |||||
| </script> | </script> | ||||
| <template> | <template> | ||||
| <view class="h-100 d-flex flex-column"> | <view class="h-100 d-flex flex-column"> | ||||
| <BackgroundBasic/> | <BackgroundBasic/> | ||||
| <NutNavbar title=""></NutNavbar> | <NutNavbar title=""></NutNavbar> | ||||
| <View class="w-100" style="overflow-x: hidden"> | |||||
| <View class="pl-3 pt-3 pr-3 h3 d-flex"> | |||||
| <View class="flex-grow-1"> | |||||
| 来访记录 | |||||
| <view class="pl-3 pt-3 pr-3 h3 d-flex"> | |||||
| <view class="flex-grow-1"> | |||||
| 我的邀约 | |||||
| </view> | |||||
| </view> | |||||
| <View class="scroll 100vh"> | |||||
| <View class="mt-3 p-3"> | |||||
| <View class="border bg-white p-3 d-flex flex-column" hover-class="card-hover-gray" @tap="goToContactNewPage()" > | |||||
| <View class="d-flex justify-content-center"> | |||||
| <Image :src="require('./invite.jpeg')" class="p-3" mode='heightFix' style="height: 15vh"/> | |||||
| </View> | |||||
| <View class="d-flex justify-content-center"> | |||||
| <View class="fas fa-plus-circle text-black-50" style="font-size: 120%"> 新邀约</View> | |||||
| </View> | |||||
| </View> | </View> | ||||
| </View> | </View> | ||||
| <View class="d-flex text-black-50 pb-2 pr-3"> | |||||
| <View class="flex-grow-1"></View> | |||||
| <View>最近30天的来访</View> | |||||
| <View v-if="!state.isContactDataLoading"> | |||||
| <View v-if="state.isAuthError"> | |||||
| <nut-empty description="连接出现问题,请稍后重试"> | |||||
| <div style="margin-top: 10px"> | |||||
| <nut-button type="default" @tap="onAuthErrorRefresh">刷新</nut-button> | |||||
| </div> | |||||
| </nut-empty> | |||||
| </View> | |||||
| <View v-else-if="state.isContactDataLoadError"> | |||||
| <nut-empty description="连接出现问题,请稍后重试"> | |||||
| <div style="margin-top: 10px"> | |||||
| <nut-button type="default" @tap="onContactDataLoadErrorRefresh">刷新</nut-button> | |||||
| </div> | |||||
| </nut-empty> | |||||
| </View> | |||||
| <View v-else> | |||||
| <View class="h4 p-3">来访联系人</View> | |||||
| <View class="container-fluid"> | |||||
| <View class="row w-100"> | |||||
| <View style="width: 25vw" v-for="item in state.normalContacts"> | |||||
| <View class="m-2 p-3 border" hover-class="card-hover-gray" @tap="goToContactEditPage(item)"> | |||||
| <View class="d-flex justify-content-center"> | |||||
| <NutBadge :value="item.isVIP?'VIP':''"> | |||||
| <NutAvatar size="normal" color="white" :bg-color="BjxHelper.mbString2RgbHex(item.name)" class="overflow-hidden"> | |||||
| <img v-if="item.avatar" :src="item.avatar" /> | |||||
| <view v-else-if="BjxHelper.getBJXFirstChar(item.name)">{{BjxHelper.getBJXFirstChar(item.name)}}</view> | |||||
| <view v-else> | |||||
| <Text className='fas fa-user fa-lg'/> | |||||
| </view> | |||||
| </NutAvatar> | |||||
| </NutBadge> | |||||
| </View> | |||||
| <View class="d-flex justify-content-center small b pt-2 text-nowrap overflow-hidden"> | |||||
| {{item.name}} | |||||
| </View> | |||||
| </View> | |||||
| </View> | |||||
| </View> | |||||
| </View> | |||||
| <View class="h4 p-3">可随时来访联系人</View> | |||||
| <View class="container-fluid"> | |||||
| <View class="row w-100"> | |||||
| <View style="width: 25vw" v-for="item in state.flexContacts"> | |||||
| <View class="m-2 p-3 border" hover-class="card-hover-gray" @tap="goToContactEditPage(item)"> | |||||
| <View class="d-flex justify-content-center"> | |||||
| <NutBadge :value="item.isVIP?'VIP':''"> | |||||
| <NutAvatar size="normal" color="white" :bg-color="BjxHelper.mbString2RgbHex(item.name)" class="overflow-hidden"> | |||||
| <img v-if="item.avatar" :src="item.avatar" /> | |||||
| <view v-else-if="BjxHelper.getBJXFirstChar(item.name)">{{BjxHelper.getBJXFirstChar(item.name)}}</view> | |||||
| <view v-else> | |||||
| <Text className='fas fa-user fa-lg'/> | |||||
| </view> | |||||
| </NutAvatar> | |||||
| </NutBadge> | |||||
| </View> | |||||
| <View class="d-flex justify-content-center small b pt-2 text-nowrap overflow-hidden"> | |||||
| {{item.name}} | |||||
| </View> | |||||
| </View> | |||||
| </View> | |||||
| </View> | |||||
| </View> | |||||
| </View> | |||||
| </View> | </View> | ||||
| </View> | |||||
| <View v-if="state.isAuthError"> | |||||
| <nut-empty description="连接出现问题,请稍后重试"> | |||||
| <div style="margin-top: 10px"> | |||||
| <nut-button type="default" @tap="onAuthErrorRefresh">刷新</nut-button> | |||||
| </div> | |||||
| </nut-empty> | |||||
| </View> | |||||
| <View class="scroll 100vh" v-else> | |||||
| <view class="scroll 100vh" v-if="!state.isPageDataLoading"> | |||||
| <Scroll-View style="height: 100vh" :scrollY="true"> | |||||
| <Notification v-for="item in state.groupedPassRecords" :item="item"/> | |||||
| <view class="container pt-5 pb-3"> | |||||
| <view class="row"> | |||||
| <view class="col"/> | |||||
| <view class="col text-center text-black-50"> | |||||
| <nut-divider> 没有更多了 </nut-divider> | |||||
| </view> | |||||
| <view class="col"/> | |||||
| </view> | |||||
| </view> | |||||
| </Scroll-View> | |||||
| </view> | |||||
| <View v-else class="skeleton"> | |||||
| <NutSkeleton v-for="_ in 10" class="pl-4 pt-4 pb-4 pr-5" height="20px" width="60vw" animated avatar avatar-size="50px" row="2"/> | |||||
| <View v-else class="d-flex flex-column"> | |||||
| <NutSkeleton v-for="_ in 10" class="p-3" height="15px" animated avatar avatar-size="50px" row="1"/> | |||||
| </View> | </View> | ||||
| </View> | </View> | ||||
| </view> | |||||
| <!-- <view class="p-4">--> | |||||
| <!-- <button open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber">使用电话号码登录</button>--> | |||||
| <!-- </view>--> | |||||
| <!-- <Counter/>--> | |||||
| <!-- <nut-cell title="展示弹出层" is-link @click="show = true"></nut-cell>--> | |||||
| <!-- <nut-popup :style="{ padding: '30px 50px' }" v-model:visible="show">正文</nut-popup>--> | |||||
| <!-- <View><Text>{{state.msg}}</Text></View>--> | |||||
| <!-- <nut-button type="primary" @click="handleClick(state.msg2)">点我</nut-button>--> | |||||
| <!-- <Add color="red" />--> | |||||
| <!-- <div class="alert alert-primary" role="alert">--> | |||||
| <!-- A simple primary alert—check it out!--> | |||||
| <!-- </div>--> | |||||
| <!-- <h1>Example heading <span class="badge bg-secondary">New</span></h1>--> | |||||
| <!-- <button type="button" class="btn btn-primary">--> | |||||
| <!-- Notifications <span class="badge text-bg-secondary">4</span>--> | |||||
| <!-- </button>--> | |||||
| <!-- <button type="button" class="btn btn-primary position-relative">--> | |||||
| <!-- Inbox--> | |||||
| <!-- <span class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-danger">--> | |||||
| <!-- 99+--> | |||||
| <!-- <span class="visually-hidden">unread messages</span>--> | |||||
| <!-- </span>--> | |||||
| <!-- </button>--> | |||||
| <!-- </view>--> | |||||
| </view> | |||||
| </template> | </template> | ||||
| @@ -1,25 +0,0 @@ | |||||
| page { | |||||
| height: 100%; | |||||
| } | |||||
| .nut-navbar { | |||||
| background: transparent; | |||||
| } | |||||
| .scroll { | |||||
| flex: 1; | |||||
| overflow: scroll; | |||||
| } | |||||
| .nut-grid-item__content { | |||||
| padding: 0; | |||||
| display:unset; | |||||
| } | |||||
| .nut-grid-item__content--border { | |||||
| border-right-width: unset; | |||||
| border-bottom-width: unset; | |||||
| } | |||||
| .nut-grid-item__content--surround { | |||||
| border-top-width: unset; | |||||
| border-left-width: unset; | |||||
| } | |||||
| @@ -1,208 +0,0 @@ | |||||
| <script lang="ts" setup> | |||||
| import Contact from "../../components/contact" | |||||
| import { Router } from 'tarojs-router-next' | |||||
| import {reactive, ref} from 'vue'; | |||||
| import './index.scss' | |||||
| import { useContactsStore, ContactData } from '../../stores/contacts' | |||||
| import { registerRouterBackListener } from 'tarojs-router-next' | |||||
| import {BjxHelper} from "../../utils"; | |||||
| import {gql} from "graphql-tag"; | |||||
| import {PinyinHelper, GQLRequest, weappAuth} from "../../utils"; | |||||
| import {useAuthStore} from "../../stores/auth"; | |||||
| // defineExpose({ | |||||
| // loadContactsFromServer, | |||||
| // }); | |||||
| const state = reactive<{ | |||||
| isAuthError: boolean, | |||||
| isContactDataLoadError: boolean, | |||||
| isContactDataLoading: boolean, | |||||
| searchQuery: string, | |||||
| normalContacts: ContactData[], | |||||
| flexContacts: ContactData[], // Generic type for now | |||||
| }>({ | |||||
| isAuthError: false, | |||||
| isContactDataLoadError: false, | |||||
| isContactDataLoading: true, | |||||
| searchQuery: "", | |||||
| normalContacts: [], | |||||
| flexContacts: [] | |||||
| }) | |||||
| const contacts = useContactsStore() | |||||
| init() | |||||
| function init() { | |||||
| state.isAuthError = false | |||||
| state.isContactDataLoadError = false | |||||
| state.isContactDataLoading = true | |||||
| weappAuth() | |||||
| .then(r => { | |||||
| contacts.loadContactsFromServer().then( | |||||
| contactList => { | |||||
| console.log("contactList", contactList) | |||||
| generateContactGroupList(contactList) | |||||
| state.isContactDataLoading = false | |||||
| }) | |||||
| .catch(e => { | |||||
| state.isAuthError = false | |||||
| state.isContactDataLoadError = true | |||||
| state.isContactDataLoading = false | |||||
| }) | |||||
| }) | |||||
| .catch(e=> { | |||||
| console.log("error", e) | |||||
| state.isAuthError = true | |||||
| state.isContactDataLoadError = false | |||||
| state.isContactDataLoading = false | |||||
| }) | |||||
| registerRouterBackListener((to, from) => { | |||||
| if ((from.url === "/pages/contact-new/index" && to.url === "/pages/invite/index") | |||||
| || (from.url === "/pages/contact-edit/index" && to.url === "/pages/invite/index") | |||||
| ) { | |||||
| generateContactGroupList(contacts.allContacts) | |||||
| } | |||||
| }) | |||||
| } | |||||
| const onAuthErrorRefresh = () => { | |||||
| init() | |||||
| } | |||||
| const onContactDataLoadErrorRefresh = () => { | |||||
| state.isContactDataLoadError = false | |||||
| state.isContactDataLoading = true | |||||
| contacts.loadContactsFromServer().then( | |||||
| contactList => { | |||||
| console.log("contactList", contactList) | |||||
| generateContactGroupList(contactList) | |||||
| state.isContactDataLoading = false | |||||
| }) | |||||
| .catch(e => { | |||||
| state.isContactDataLoadError = true | |||||
| state.isContactDataLoading = false | |||||
| }) | |||||
| } | |||||
| const generateContactGroupList = (contactList: ContactData[]) => { | |||||
| state.normalContacts = [] | |||||
| state.flexContacts = [] | |||||
| for (const item of contactList) { | |||||
| if (item.flexVisit === true) state.flexContacts.push(item) | |||||
| else state.normalContacts.push(item) | |||||
| } | |||||
| } | |||||
| const goToContactNewPage = () => { | |||||
| Router.toContactNew() | |||||
| } | |||||
| const goToContactEditPage = (item) => { | |||||
| Router.toContactEdit({ data: item }) | |||||
| } | |||||
| </script> | |||||
| <template> | |||||
| <view class="h-100 d-flex flex-column"> | |||||
| <BackgroundBasic/> | |||||
| <NutNavbar title=""></NutNavbar> | |||||
| <view class="pl-3 pt-3 pr-3 h3 d-flex"> | |||||
| <view class="flex-grow-1"> | |||||
| 我的邀约 | |||||
| </view> | |||||
| </view> | |||||
| <View class="scroll 100vh"> | |||||
| <View class="mt-3 p-3"> | |||||
| <View class="border bg-white p-3 d-flex flex-column" hover-class="card-hover-gray" @tap="goToContactNewPage()" > | |||||
| <View class="d-flex justify-content-center"> | |||||
| <Image :src="require('./invite.jpeg')" class="p-3" mode='heightFix' style="height: 15vh"/> | |||||
| </View> | |||||
| <View class="d-flex justify-content-center"> | |||||
| <View class="fas fa-plus-circle text-black-50" style="font-size: 120%"> 新邀约</View> | |||||
| </View> | |||||
| </View> | |||||
| </View> | |||||
| <View v-if="!state.isContactDataLoading"> | |||||
| <View v-if="state.isAuthError"> | |||||
| <nut-empty description="连接出现问题,请稍后重试"> | |||||
| <div style="margin-top: 10px"> | |||||
| <nut-button type="default" @tap="onAuthErrorRefresh">刷新</nut-button> | |||||
| </div> | |||||
| </nut-empty> | |||||
| </View> | |||||
| <View v-else-if="state.isContactDataLoadError"> | |||||
| <nut-empty description="连接出现问题,请稍后重试"> | |||||
| <div style="margin-top: 10px"> | |||||
| <nut-button type="default" @tap="onContactDataLoadErrorRefresh">刷新</nut-button> | |||||
| </div> | |||||
| </nut-empty> | |||||
| </View> | |||||
| <View v-else> | |||||
| <View class="h4 p-3">来访联系人</View> | |||||
| <View class="container-fluid"> | |||||
| <View class="row w-100"> | |||||
| <View style="width: 25vw" v-for="item in state.normalContacts"> | |||||
| <View class="m-2 p-3 border" hover-class="card-hover-gray" @tap="goToContactEditPage(item)"> | |||||
| <View class="d-flex justify-content-center"> | |||||
| <NutBadge :value="item.isVIP?'VIP':''"> | |||||
| <NutAvatar size="normal" color="white" :bg-color="BjxHelper.mbString2RgbHex(item.name)" class="overflow-hidden"> | |||||
| <img v-if="item.avatar" :src="item.avatar" /> | |||||
| <view v-else-if="BjxHelper.getBJXFirstChar(item.name)">{{BjxHelper.getBJXFirstChar(item.name)}}</view> | |||||
| <view v-else> | |||||
| <Text className='fas fa-user fa-lg'/> | |||||
| </view> | |||||
| </NutAvatar> | |||||
| </NutBadge> | |||||
| </View> | |||||
| <View class="d-flex justify-content-center small b pt-2 text-nowrap overflow-hidden"> | |||||
| {{item.name}} | |||||
| </View> | |||||
| </View> | |||||
| </View> | |||||
| </View> | |||||
| </View> | |||||
| <View class="h4 p-3">可随时来访联系人</View> | |||||
| <View class="container-fluid"> | |||||
| <View class="row w-100"> | |||||
| <View style="width: 25vw" v-for="item in state.flexContacts"> | |||||
| <View class="m-2 p-3 border" hover-class="card-hover-gray" @tap="goToContactEditPage(item)"> | |||||
| <View class="d-flex justify-content-center"> | |||||
| <NutBadge :value="item.isVIP?'VIP':''"> | |||||
| <NutAvatar size="normal" color="white" :bg-color="BjxHelper.mbString2RgbHex(item.name)" class="overflow-hidden"> | |||||
| <img v-if="item.avatar" :src="item.avatar" /> | |||||
| <view v-else-if="BjxHelper.getBJXFirstChar(item.name)">{{BjxHelper.getBJXFirstChar(item.name)}}</view> | |||||
| <view v-else> | |||||
| <Text className='fas fa-user fa-lg'/> | |||||
| </view> | |||||
| </NutAvatar> | |||||
| </NutBadge> | |||||
| </View> | |||||
| <View class="d-flex justify-content-center small b pt-2 text-nowrap overflow-hidden"> | |||||
| {{item.name}} | |||||
| </View> | |||||
| </View> | |||||
| </View> | |||||
| </View> | |||||
| </View> | |||||
| </View> | |||||
| </View> | |||||
| <View v-else class="d-flex flex-column"> | |||||
| <NutSkeleton v-for="_ in 10" class="p-3" height="15px" animated avatar avatar-size="50px" row="1"/> | |||||
| </View> | |||||
| </View> | |||||
| </view> | |||||
| </template> | |||||
| @@ -1,6 +1,6 @@ | |||||
| export default definePageConfig({ | export default definePageConfig({ | ||||
| navigationBarTitleText: '', | navigationBarTitleText: '', | ||||
| usingComponents: {}, | |||||
| navigationStyle: 'custom', | navigationStyle: 'custom', | ||||
| disableScroll: true | |||||
| disableScroll: true, | |||||
| usingComponents: {}, | |||||
| }) | }) | ||||
| @@ -0,0 +1,18 @@ | |||||
| page { | |||||
| height: 100%; | |||||
| } | |||||
| .nut-navbar { | |||||
| background: transparent; | |||||
| } | |||||
| .scroll { | |||||
| flex: 1; | |||||
| overflow: scroll; | |||||
| } | |||||
| .skeleton { | |||||
| flex: 1; | |||||
| overflow: hidden; | |||||
| } | |||||
| @@ -0,0 +1,169 @@ | |||||
| <script setup lang="ts"> | |||||
| import { reactive } from 'vue' | |||||
| import { View } from '@tarojs/components' | |||||
| import './index.scss' | |||||
| import {weappAuth} from "../../utils"; | |||||
| import {GroupedPassRecords, usePassRecordsStore} from "../../stores/pass-records"; | |||||
| import {useContactsStore} from "../../stores/contacts"; | |||||
| const state = reactive<{ | |||||
| isPageDataLoading: boolean, | |||||
| isAuthError: boolean, | |||||
| groupedPassRecords: GroupedPassRecords[], | |||||
| }>({ | |||||
| isPageDataLoading: true, | |||||
| isAuthError: false, | |||||
| groupedPassRecords: [], | |||||
| }) | |||||
| const passRecords = usePassRecordsStore() | |||||
| const contacts = useContactsStore() | |||||
| init() | |||||
| function init() { | |||||
| state.isAuthError = false | |||||
| state.isPageDataLoading = true | |||||
| weappAuth().then(r => { | |||||
| console.log(r) | |||||
| passRecords.loadPassRecordsFromServer().then( passRecords => { | |||||
| state.groupedPassRecords = passRecords | |||||
| console.log("aaa",state.groupedPassRecords ) | |||||
| // console.log(state.groupedPassRecords) | |||||
| state.isPageDataLoading = false | |||||
| }) | |||||
| .catch(error => { | |||||
| console.log("error", error) | |||||
| state.isAuthError = true | |||||
| state.isPageDataLoading = false | |||||
| }) | |||||
| }).catch(e => { | |||||
| console.log("error", e) | |||||
| state.isAuthError = true | |||||
| state.isPageDataLoading = false | |||||
| }) | |||||
| } | |||||
| const onAuthErrorRefresh = () => { | |||||
| init() | |||||
| } | |||||
| // const onPullDownRefresh = () => { | |||||
| // console.log("onPullDownRefresh") | |||||
| // state.isRefresherTriggered = false | |||||
| // } | |||||
| function onPullDownRefresh (e) { | |||||
| console.log("onPullDownRefresh", e) | |||||
| // state.isRefresherTriggered = false | |||||
| } | |||||
| // | |||||
| // | |||||
| // const show = ref(false); | |||||
| // | |||||
| // const state = reactive({ | |||||
| // msg: '欢迎使用 NutUI4.0 开发小程序', | |||||
| // msg2: '你成功了~', | |||||
| // isVisible1: false, | |||||
| // val: '' | |||||
| // }) | |||||
| // | |||||
| // const handleClick = msg => { | |||||
| // state.msg = msg | |||||
| // } | |||||
| // | |||||
| // useDidShow(() => { | |||||
| // console.log("did show is run xxxxxxx.") | |||||
| // }) | |||||
| // | |||||
| // useLoad(() => { | |||||
| // console.log("use load is run xxxxxxx.") | |||||
| // }) | |||||
| </script> | |||||
| <template> | |||||
| <view class="h-100 d-flex flex-column"> | |||||
| <BackgroundBasic/> | |||||
| <NutNavbar title=""></NutNavbar> | |||||
| <View class="w-100" style="overflow-x: hidden"> | |||||
| <View class="pl-3 pt-3 pr-3 h3 d-flex"> | |||||
| <View class="flex-grow-1"> | |||||
| 来访记录 | |||||
| </View> | |||||
| </View> | |||||
| <View class="d-flex text-black-50 pb-2 pr-3"> | |||||
| <View class="flex-grow-1"></View> | |||||
| <View>最近30天的来访</View> | |||||
| </View> | |||||
| </View> | |||||
| <View v-if="state.isAuthError"> | |||||
| <nut-empty description="连接出现问题,请稍后重试"> | |||||
| <div style="margin-top: 10px"> | |||||
| <nut-button type="default" @tap="onAuthErrorRefresh">刷新</nut-button> | |||||
| </div> | |||||
| </nut-empty> | |||||
| </View> | |||||
| <View class="scroll 100vh" v-else> | |||||
| <view class="scroll 100vh" v-if="!state.isPageDataLoading"> | |||||
| <Scroll-View style="height: 100vh" :scrollY="true"> | |||||
| <Notification v-for="item in state.groupedPassRecords" :item="item"/> | |||||
| <view class="container pt-5 pb-3"> | |||||
| <view class="row"> | |||||
| <view class="col"/> | |||||
| <view class="col text-center text-black-50"> | |||||
| <nut-divider> 没有更多了 </nut-divider> | |||||
| </view> | |||||
| <view class="col"/> | |||||
| </view> | |||||
| </view> | |||||
| </Scroll-View> | |||||
| </view> | |||||
| <View v-else class="skeleton"> | |||||
| <NutSkeleton v-for="_ in 10" class="pl-4 pt-4 pb-4 pr-5" height="20px" width="60vw" animated avatar avatar-size="50px" row="2"/> | |||||
| </View> | |||||
| </View> | |||||
| </view> | |||||
| <!-- <view class="p-4">--> | |||||
| <!-- <button open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber">使用电话号码登录</button>--> | |||||
| <!-- </view>--> | |||||
| <!-- <Counter/>--> | |||||
| <!-- <nut-cell title="展示弹出层" is-link @click="show = true"></nut-cell>--> | |||||
| <!-- <nut-popup :style="{ padding: '30px 50px' }" v-model:visible="show">正文</nut-popup>--> | |||||
| <!-- <View><Text>{{state.msg}}</Text></View>--> | |||||
| <!-- <nut-button type="primary" @click="handleClick(state.msg2)">点我</nut-button>--> | |||||
| <!-- <Add color="red" />--> | |||||
| <!-- <div class="alert alert-primary" role="alert">--> | |||||
| <!-- A simple primary alert—check it out!--> | |||||
| <!-- </div>--> | |||||
| <!-- <h1>Example heading <span class="badge bg-secondary">New</span></h1>--> | |||||
| <!-- <button type="button" class="btn btn-primary">--> | |||||
| <!-- Notifications <span class="badge text-bg-secondary">4</span>--> | |||||
| <!-- </button>--> | |||||
| <!-- <button type="button" class="btn btn-primary position-relative">--> | |||||
| <!-- Inbox--> | |||||
| <!-- <span class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-danger">--> | |||||
| <!-- 99+--> | |||||
| <!-- <span class="visually-hidden">unread messages</span>--> | |||||
| <!-- </span>--> | |||||
| <!-- </button>--> | |||||
| <!-- </view>--> | |||||
| </template> | |||||