Bläddra i källkod

更访客基本信息

tags/AL.0.8.0_20240113_base
yuan 1 år sedan
förälder
incheckning
a9374b0044
9 ändrade filer med 267 tillägg och 92 borttagningar
  1. +1
    -1
      components.d.ts
  2. +20
    -22
      src/components/contact-form/index.vue
  3. +2
    -2
      src/components/contact/index.vue
  4. +29
    -2
      src/pages/contact-edit/index.vue
  5. +60
    -12
      src/pages/contact/index.vue
  6. +54
    -31
      src/pages/index/index.vue
  7. +90
    -0
      src/stores/contact-item.ts
  8. +9
    -21
      src/stores/contacts.ts
  9. +2
    -1
      src/utils/GQLRequest.ts

+ 1
- 1
components.d.ts Visa fil

@@ -7,7 +7,6 @@ export {}

declare module 'vue' {
export interface GlobalComponents {
Auth: typeof import('./src/components/Auth.vue')['default']
BackgroundBasic: typeof import('./src/components/background-basic/index.vue')['default']
Contact: typeof import('./src/components/contact/index.vue')['default']
ContactForm: typeof import('./src/components/contact-form/index.vue')['default']
@@ -23,6 +22,7 @@ declare module 'vue' {
NutCollapseItem: typeof import('@nutui/nutui-taro')['CollapseItem']
NutDivider: typeof import('@nutui/nutui-taro')['Divider']
NutElevator: typeof import('@nutui/nutui-taro')['Elevator']
NutEmpty: typeof import('@nutui/nutui-taro')['Empty']
NutForm: typeof import('@nutui/nutui-taro')['Form']
NutFormItem: typeof import('@nutui/nutui-taro')['FormItem']
NutInput: typeof import('@nutui/nutui-taro')['Input']


+ 20
- 22
src/components/contact-form/index.vue Visa fil

@@ -7,18 +7,16 @@ import { Router } from 'tarojs-router-next'
import { reactive, ref } from 'vue';
import {BjxHelper} from "../../utils";
import {useContactsStore} from "../../stores/contacts";
import {useContactItemStore} from "../../stores/contact-item";

const props = defineProps(['data'])

const contacts = useContactsStore()
const contact = useContactItemStore()

const state = reactive({
isNickNameSuggestionsShow: false,
contactData: props.data ? props.data : contacts.getEmptyContactData(),
newAvatar: '',
number: '',
// lastName: BjxHelper.getBJXFirstChar(name),
date: '',
isDateSelectorVisible: false
});

@@ -29,8 +27,8 @@ const openSwitch = (param) => {
const closeSwitch = (param) => {
state[`${param}`] = false;
};
const setChooseValue = (param) => {
state.date = param[3];
const setChooseDate = (param) => {
contact.contact.nextVisitDate = param[3]
};

function setShowSuggestions(isShow: Boolean) {
@@ -53,7 +51,7 @@ const updateNickName = (value) => {
state.isNickNameSuggestionsShow = false
}
else {
state.contactData.nickName = BjxHelper.getBJXFirstChar(state.contactData.name) + value;
contact.contact.nickName = BjxHelper.getBJXFirstChar(contact.contact.name) + value;
}
}
</script>
@@ -65,27 +63,27 @@ const updateNickName = (value) => {
<view>
<view class="d-flex justify-content-center">
<nut-avatar size="192" @click="updateFacePhoto" class="overflow-hidden">
<img v-if="state.contactData.avatar" :src="state.contactData.avatar" />
<img v-if="contact.contact.avatar" :src="contact.contact.avatar" />
<view v-else class="d-flex align-items-center justify-content-center h-100 w-100">
<Text class="fas fa-user fa-6x"></Text>
</view>
</nut-avatar>
</view>
<view class="d-flex justify-content-center pt-3">
<view class="btn btn-secondary badge-pill" @tap="updateFacePhoto">{{state.contactData.avatar || state.newAvatar ?'更换':'添加'}}面部识别照片</view>
<view class="btn btn-secondary badge-pill" @tap="updateFacePhoto">{{contact.contact.avatar || state.newAvatar ?'更换':'添加'}}面部识别照片</view>
</view>
</view>
</nut-form-item>
<nut-form-item label="姓名">
<nut-input v-model="state.contactData.name" class="nut-input-text" />
<nut-input v-model="contact.contact.name" class="nut-input-text" />
</nut-form-item>
<nut-form-item label="称呼">
<nut-input v-model="state.contactData.nickName" @change="state.isNickNameSuggestionsShow = false" class="nut-input-text" @focus="setShowSuggestions(true)" @blur="setShowSuggestions(false)" />
<nut-input v-model="contact.contact.nickName" @change="state.isNickNameSuggestionsShow = false" class="nut-input-text" @focus="setShowSuggestions(true)" @blur="setShowSuggestions(false)" />
</nut-form-item>
<view class="suggestions" style="background-color: #EEE" v-show="state.isNickNameSuggestionsShow">
<view @tap="updateNickName('先生')">{{BjxHelper.getBJXFirstChar(state.contactData.name)}}先生</view>
<view @tap="updateNickName('女士')">{{BjxHelper.getBJXFirstChar(state.contactData.name)}}女士</view>
<view @tap="updateNickName('小姐')">{{BjxHelper.getBJXFirstChar(state.contactData.name)}}小姐</view>
<view @tap="updateNickName('先生')">{{BjxHelper.getBJXFirstChar(contact.contact.name)}}先生</view>
<view @tap="updateNickName('女士')">{{BjxHelper.getBJXFirstChar(contact.contact.name)}}女士</view>
<view @tap="updateNickName('小姐')">{{BjxHelper.getBJXFirstChar(contact.contact.name)}}小姐</view>
<view @tap="updateNickName(null)">
<View class="d-flex">
<View class="flex-grow-1">
@@ -97,31 +95,31 @@ const updateNickName = (value) => {
</view>

<nut-form-item label="电话">
<nut-input v-model="state.contactData.phone" class="nut-input-text" />
<nut-input v-model="contact.contact.phone" class="nut-input-text" />
</nut-form-item>
<nut-form-item label="公司">
<nut-input v-model="state.contactData.company" class="nut-input-text" />
<nut-input v-model="contact.contact.company" class="nut-input-text" />
</nut-form-item>

<nut-form-item label="VIP">
<view class="d-flex">
<view class="flex-grow-1"></view>
<nut-switch v-model="state.contactData.isVIP" active-color="blue" />
<nut-switch v-model="contact.contact.isVIP" active-color="blue" />
</view>
</nut-form-item>

<nut-form-item label="可随时来访">
<view class="d-flex">
<view class="flex-grow-1"></view>
<nut-switch v-model="state.contactData.flexVisit" active-color="blue" />
<nut-switch v-model="contact.contact.flexVisit" active-color="blue" />
</view>
</nut-form-item>

<nut-form-item label="下次到访日期" v-show="!state.contactData.flexVisit">
<nut-form-item label="下次到访日期" v-show="!contact.contact.flexVisit">
<view class="d-flex calendar">
<view class="flex-grow-1"></view>
<view class="text-dark" @tap="openSwitch('isDateSelectorVisible')">
{{state.date ? state.date : '请选择'}}
{{contact.contact.nextVisitDate ? contact.contact.nextVisitDate : '请选择'}}
</view>
</view>
</nut-form-item>
@@ -131,8 +129,8 @@ const updateNickName = (value) => {
<nut-calendar
v-model:visible="state.isDateSelectorVisible"
@close="closeSwitch('isDateSelectorVisible')"
@choose="setChooseValue"
:default-value="state.date"
@choose="setChooseDate"
:default-value="contact.contact.nextVisitDate"
:is-auto-back-fill="true"
>
</nut-calendar>


+ 2
- 2
src/components/contact/index.vue Visa fil

@@ -10,8 +10,8 @@ const props = defineProps(['items'])
// const elevatorHeight = ref(ScreenHelper.getScreenHeight() - ScreenHelper.getStatusBarHeight() - ScreenHelper.getWindowBarHeight())

const clickItem = (key: string, item: ContactData) => {
console.log(key);
console.log(item.name);
console.log(key, item.name);
console.log(item);

Router.toContactEdit({ data: item })
}


+ 29
- 2
src/pages/contact-edit/index.vue Visa fil

@@ -1,14 +1,41 @@
<script setup>
import { Router } from 'tarojs-router-next'
import './index.scss'
import {useContactItemStore} from "../../stores/contact-item";
import { useContactsStore } from "../../stores/contacts";
import Taro from "@tarojs/taro";


const contactData = Router.getData()
// const contactData = JSON.stringify(contactDataString)
const contact = useContactItemStore()
const contacts = useContactsStore()
contact.setContact(contactData)

const goBack = () => {
Router.back()
}
const onSaveClicked = () => {
Taro.showLoading({
title: 'loading',
})

console.log("onSaveClicked")
console.log(contact.contact)
contact.updateVisitor().then(r => {
contacts.loadContactsFromServer().then( contactsResult => {
Taro.hideLoading()
Router.back()
})
}).catch(error => {
Taro.hideLoading()
Taro.showToast({
title: '网络异常,请稍候重试',
icon: 'none',
duration: 2000
})
console.log("error", error)
})
}
</script>

<template>
@@ -26,7 +53,7 @@ const goBack = () => {
<view class="text-black-50">更新来访联系人信息,并设置下次到访时间</view>
</view>
<view class="d-flex align-items-end">
<view class="text-primary save-button">保存</view>
<view class="text-primary save-button" @tap="onSaveClicked">保存</view>
</view>
</view>



+ 60
- 12
src/pages/contact/index.vue Visa fil

@@ -15,10 +15,14 @@ import {useAuthStore} from "../../stores/auth";
// });

const state = reactive<{
isContactDataLoading: boolean;
searchQuery: string;
contactGroupedList: any[]; // Generic type for now
isAuthError: boolean,
isContactDataLoadError: boolean,
isContactDataLoading: boolean,
searchQuery: string,
contactGroupedList: any[], // Generic type for now
}>({
isAuthError: false,
isContactDataLoadError: false,
isContactDataLoading: true,
searchQuery: "",
contactGroupedList: [],
@@ -26,9 +30,11 @@ const state = reactive<{
const contacts = useContactsStore()


asyncInit()
init()

async function asyncInit() {
function init() {
state.isAuthError = false
state.isContactDataLoadError = false
state.isContactDataLoading = true
weappAuth()
.then(r => {
@@ -38,6 +44,35 @@ async function asyncInit() {
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
})
}

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
})
}

@@ -85,14 +120,27 @@ const generateContactGroupList = (contactList: ContactData[]) => {
</View>


<view class="scroll 100vh" 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 class="scroll 100vh" v-else>
<view class="scroll 100vh" v-if="!state.isContactDataLoading">
<Contact :items="state.contactGroupedList"/>
</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 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>

+ 54
- 31
src/pages/index/index.vue Visa fil

@@ -12,15 +12,29 @@ import {weappAuth} from "../../utils";

const state = reactive<{
isPageDataLoading: boolean,
isAuthError: boolean,
}>({
isPageDataLoading: true,
isAuthError: false
})

asyncInit()
init()

function init() {
state.isAuthError = false
state.isPageDataLoading = true
weappAuth().then(r => {
console.log(r)
state.isPageDataLoading = false
}).catch(e => {
console.log("error", e)
state.isAuthError = true
state.isPageDataLoading = false
})
}

async function asyncInit() {
await weappAuth()
state.isPageDataLoading = false
const onAuthErrorRefresh = () => {
init()
}
//
//
@@ -68,35 +82,44 @@ async function asyncInit() {
</View>
</View>

<view class="scroll 100vh" v-if="!state.isPageDataLoading">
<Scroll-View :scroll-y="true">
<Notification name="" company="小明科技2" is-vip="true" pass-date="2023-12-25" pass-time="22:22:22" today-pass-time='["22:22:21","22:22:20"]'/>
<Notification name="王远" company="joydata科技" is-vip="true" pass-date="2023-12-25" pass-time="22:22:22" today-pass-time='[]'/>
<Notification name="华雨" company="joydata科技" is-vip="false" pass-date="2023-12-25" pass-time="22:22:22" today-pass-time='["22:22:21"]'/>
<Notification name="邸为荣" company="" is-vip="false" pass-date="2023-12-25" pass-time="22:22:22" today-pass-time='["22:22:21","22:22:20"]'/>

<Notification name="邸为荣" company="" is-vip="false" pass-date="2023-12-25" pass-time="22:22:22" today-pass-time='["22:22:21","22:22:20"]'/>
<Notification name="邸为荣" company="" is-vip="false" pass-date="2023-12-25" pass-time="22:22:22" today-pass-time='["22:22:21","22:22:20"]'/>
<Notification name="邸为荣" company="" is-vip="false" pass-date="2023-12-25" pass-time="22:22:22" today-pass-time='["22:22:21","22:22:20"]'/>


<Notification name="邸为荣" company="" is-vip="false" pass-date="2023-12-25" pass-time="22:22:22" today-pass-time='["22:22:21","22:22:20"]'/>
<Notification name="邸为荣" company="" is-vip="false" pass-date="2023-12-25" pass-time="22:22:22" today-pass-time='["22:22:21","22:22:20"]'/>
<Notification name="邸为荣" company="" is-vip="false" pass-date="2023-12-25" pass-time="22:22:22" today-pass-time='["22:22:21","22:22:20"]'/>

<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 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 :scroll-y="true">
<Notification name="" company="小明科技2" is-vip="true" pass-date="2023-12-25" pass-time="22:22:22" today-pass-time='["22:22:21","22:22:20"]'/>
<Notification name="王远" company="joydata科技" is-vip="true" pass-date="2023-12-25" pass-time="22:22:22" today-pass-time='[]'/>
<Notification name="华雨" company="joydata科技" is-vip="false" pass-date="2023-12-25" pass-time="22:22:22" today-pass-time='["22:22:21"]'/>
<Notification name="邸为荣" company="" is-vip="false" pass-date="2023-12-25" pass-time="22:22:22" today-pass-time='["22:22:21","22:22:20"]'/>

<Notification name="邸为荣" company="" is-vip="false" pass-date="2023-12-25" pass-time="22:22:22" today-pass-time='["22:22:21","22:22:20"]'/>
<Notification name="邸为荣" company="" is-vip="false" pass-date="2023-12-25" pass-time="22:22:22" today-pass-time='["22:22:21","22:22:20"]'/>
<Notification name="邸为荣" company="" is-vip="false" pass-date="2023-12-25" pass-time="22:22:22" today-pass-time='["22:22:21","22:22:20"]'/>


<Notification name="邸为荣" company="" is-vip="false" pass-date="2023-12-25" pass-time="22:22:22" today-pass-time='["22:22:21","22:22:20"]'/>
<Notification name="邸为荣" company="" is-vip="false" pass-date="2023-12-25" pass-time="22:22:22" today-pass-time='["22:22:21","22:22:20"]'/>
<Notification name="邸为荣" company="" is-vip="false" pass-date="2023-12-25" pass-time="22:22:22" today-pass-time='["22:22:21","22:22:20"]'/>

<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 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"/>
</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>



+ 90
- 0
src/stores/contact-item.ts Visa fil

@@ -0,0 +1,90 @@
// https://pinia.esm.dev/introduction.html
import { defineStore } from 'pinia'
import {GQLRequest} from "../utils";
import {gql} from "graphql-tag";
import {ContactData} from "./contacts";
import {ref, Ref, UnwrapRef} from "vue";

export const useContactItemStore = defineStore('contact-item', () => {

const contact: Ref<UnwrapRef<ContactData>> = ref(getEmptyContactData())

function setContact(contactItem: ContactData) {
contact.value = contactItem
console.log("setContact", contact.value)
}

function getEmptyContactData(): ContactData {
return {
id: undefined,
name: "",
isVIP: false,
flexVisit: false,
isBlock: false,
nickName: "",
avatar: "",
phone: "",
company: "",
nextVisitDate: undefined,
firstCharPinyin: ""
}
}

const CREATE_VISITOR = gql`
mutation CreateVisitor($name: String!, $nickName: String, $phone: String, $company: String, $isVIP: Boolean, $flexVisit: Boolean, $resourceId: Long ) {
createVisitor( input: {
name: $name,
nickname: $nickName,
phone: $phone,
visitorCompany: $company,
isVip: $isVIP,
flexVisit: $flexVisit,
resourceId: $resourceId
} ) {
result
}
}
`

const UPDATE_VISITOR = gql`
mutation UpdateVisitor($id: Long!, $name: String!, $nickName: String, $phone: String, $company: String, $isVIP: Boolean, $flexVisit: Boolean, $resourceId: Long ) {
updateVisitor( input: {
id: $id,
name: $name,
nickname: $nickName,
phone: $phone,
visitorCompany: $company,
isVip: $isVIP,
flexVisit: $flexVisit,
resourceId: $resourceId
} )
}
`

function createVisitor() {
const name = contact.value.name
const nickName = contact.value.nickName
const phone = contact.value.phone
const company = contact.value.company
const isVIP = contact.value.isVIP
const flexVisit = contact.value.flexVisit

return GQLRequest.query(CREATE_VISITOR, { name, nickName, phone, company, isVIP, flexVisit })
}

function updateVisitor() {
const id = contact.value.id
const name = contact.value.name
const nickName = contact.value.nickName
const phone = contact.value.phone
const company = contact.value.company
const isVIP = contact.value.isVIP
const flexVisit = contact.value.flexVisit

console.log(contact.value)
return GQLRequest.query(UPDATE_VISITOR, {id, name, nickName, phone, company, isVIP, flexVisit })
}


return { contact, setContact, createVisitor, updateVisitor}
})

+ 9
- 21
src/stores/contacts.ts Visa fil

@@ -31,10 +31,13 @@ export const useContactsStore = defineStore('contacts', () => {
id
name
nickname
phone
type
visitorCompany
avatar
phone
isVip
flexVisit
isBlock
}
}
`
@@ -48,7 +51,7 @@ export const useContactsStore = defineStore('contacts', () => {
if (result.code == 500) {
reject("Network Error")
} else {
// console.log(result)
console.log(result)
for (let item of result.data.visitors) {
items.push({
id: item.id,
@@ -57,9 +60,9 @@ export const useContactsStore = defineStore('contacts', () => {
avatar: item.avatar,
company: item.visitorCompany,
phone: item.phone,
flexVisit: "",
isBlock: "",
isVIP: "",
flexVisit: item.flexVisit,
isBlock: item.isBlock,
isVIP: item.isVip,
firstCharPinyin: PinyinHelper.getPinyinGroupName(item.name)
} as ContactData)
}
@@ -83,22 +86,7 @@ export const useContactsStore = defineStore('contacts', () => {
return searchedContacts
}

function getEmptyContactData(): ContactData {
return {
id: undefined,
name: "",
isVIP: false,
flexVisit: false,
isBlock: false,
nickName: "",
avatar: "",
phone: "",
company: "",
nextVisitDate: undefined,
firstCharPinyin: ""
}
}
return { allContacts , isContactsLoaded, loadContactsFromServer, searchContacts, getEmptyContactData}
return { allContacts , isContactsLoaded, loadContactsFromServer, searchContacts}
})

// You can even use a function (similar to a component setup()) to define a Store for more advanced use cases:


+ 2
- 1
src/utils/GQLRequest.ts Visa fil

@@ -13,7 +13,8 @@ export class GQLRequest {
},
data: JSON.stringify({ query: print(documentNode), variables: variable }),
success: result => {
if (result.statusCode == 200) resolve(result.data)
if ((result.data as any).hasOwnProperty("errors")) reject(result)
else if (result.statusCode == 200) resolve(result.data)
else reject(result)
},
fail: res => reject(res)


Laddar…
Avbryt
Spara