@@ -12,6 +12,7 @@ declare module 'vue' { | |||
ContactForm: typeof import('./src/components/contact-form/index.vue')['default'] | |||
Counter: typeof import('./src/components/Counter.vue')['default'] | |||
ExternalLink: typeof import('./src/components/ExternalLink.vue')['default'] | |||
MyInfoForm: typeof import('./src/components/my-info-form/index.vue')['default'] | |||
Notification: typeof import('./src/components/notification/index.vue')['default'] | |||
NutActionSheet: typeof import('@nutui/nutui-taro')['ActionSheet'] | |||
NutAvatar: typeof import('@nutui/nutui-taro')['Avatar'] | |||
@@ -56,6 +56,7 @@ | |||
"dayjs": "^1.11.10", | |||
"graphql": "^16.8.1", | |||
"graphql-tag": "^2.12.6", | |||
"install": "^0.13.0", | |||
"pinia": "^2.1.7", | |||
"taro-icons": "^0.4.0", | |||
"tarojs-router-next": "^3.4.0", | |||
@@ -1,5 +1,5 @@ | |||
{ | |||
"miniprogramRoot": "./dist", | |||
"miniprogramRoot": "dist/", | |||
"projectname": "wxapp-visitor-invite", | |||
"description": "", | |||
"appid": "wx72b4f0e248fc1b2b", | |||
@@ -9,7 +9,24 @@ | |||
"enhance": false, | |||
"compileHotReLoad": false, | |||
"postcss": false, | |||
"minified": false | |||
"minified": false, | |||
"babelSetting": { | |||
"ignore": [], | |||
"disablePlugins": [], | |||
"outputPath": "" | |||
} | |||
}, | |||
"compileType": "miniprogram" | |||
} | |||
"compileType": "miniprogram", | |||
"libVersion": "3.3.1", | |||
"isGameTourist": false, | |||
"srcMiniprogramRoot": "dist/", | |||
"packOptions": { | |||
"ignore": [], | |||
"include": [] | |||
}, | |||
"condition": {}, | |||
"editorSetting": { | |||
"tabIndent": "insertSpaces", | |||
"tabSize": 2 | |||
} | |||
} |
@@ -0,0 +1,7 @@ | |||
{ | |||
"description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html", | |||
"projectname": "wxapp-visitor-invite", | |||
"setting": { | |||
"compileHotReLoad": true | |||
} | |||
} |
@@ -10,7 +10,8 @@ export default defineAppConfig({ | |||
'pages/web-view/index', | |||
'pages/contact-pass-records/index', | |||
'pages/contact-edit-logs/index', | |||
'pages/contact-send-invite-sms/index' | |||
'pages/contact-send-invite-sms/index', | |||
'pages/my-info/index' | |||
], | |||
window: { | |||
backgroundTextStyle: 'light', | |||
@@ -0,0 +1,3 @@ | |||
{ | |||
"component": true | |||
} |
@@ -0,0 +1,31 @@ | |||
.nut-cell { | |||
background: transparent !important; | |||
} | |||
.nut-cell-group__wrap { | |||
background: transparent !important; | |||
} | |||
.suggestions { | |||
position: absolute; | |||
z-index: 10; | |||
background-color: #FFF; | |||
width: 100vw; | |||
border: solid 1px #DDD; | |||
} | |||
.suggestions > view { | |||
padding: 30px 20px 30px 50px; | |||
border-bottom: solid 1px #DDD; | |||
color: #888; | |||
} | |||
.label { | |||
padding: 30px 20px 10px 50px; | |||
color: #666; | |||
} | |||
.calendar > .nut-cell { | |||
padding: 0; | |||
} | |||
.nut-avatar-cropper::after, .nut-avatar-cropper__edit-text { | |||
background-color: transparent; | |||
} |
@@ -0,0 +1,63 @@ | |||
<script setup lang="ts"> | |||
import "./index.scss"; | |||
import Taro from "@tarojs/taro"; | |||
import {reactive, ref} from 'vue'; | |||
import {ScreenHelper, Session} from "../../utils"; | |||
import {useStaffItemStore} from "../../stores/my-info"; | |||
const me = Session.get("staff") | |||
const staff = useStaffItemStore() | |||
const screenWidth = ScreenHelper.getScreenWidth() | |||
const state = reactive({ | |||
newAvatar: undefined | |||
}); | |||
const updateFacePhoto = () => { | |||
Taro.chooseImage({ | |||
count: 1, // 默认9 | |||
sizeType: ['compressed'], // 可以指定是原图还是压缩图,默认二者都有 | |||
success: function (res) { | |||
// 返回选定照片的本地文件路径列表,tempFilePath可以作为img标签的src属性显示图片 | |||
state.newAvatar = res.tempFilePaths | |||
console.log(state.newAvatar) | |||
}, | |||
}) | |||
} | |||
</script> | |||
<template> | |||
<nut-form> | |||
<nut-form-item> | |||
<view> | |||
<view class="d-flex justify-content-center"> | |||
<nut-avatar :size="Math.floor(screenWidth/3)" @click="updateFacePhoto" class="overflow-hidden"> | |||
<img v-if="state.newAvatar" :src="state.newAvatar" alt=""/> | |||
<img v-else-if="me.avatar" :src="me.avatar" alt=""/> | |||
<view v-else class="d-flex align-items-center justify-content-center h-100 w-100"> | |||
<Text class="fas fa-user fa-5x"></Text> | |||
</view> | |||
</nut-avatar> | |||
</view> | |||
<view class="d-flex justify-content-center pt-3"> | |||
<view class="btn-sm btn btn-secondary badge-pill" @tap="updateFacePhoto">{{me.avatar || state.newAvatar ?'更换':'添加'}}面部识别照片</view> | |||
</view> | |||
</view> | |||
</nut-form-item> | |||
<nut-form-item label="姓名"> | |||
<nut-input v-model="staff.staff.userName" class="nut-input-text" /> | |||
</nut-form-item> | |||
<nut-form-item label="称呼"> | |||
<nut-input v-model="staff.staff.nickName" class="nut-input-text"> | |||
</nut-input> | |||
</nut-form-item> | |||
<nut-form-item label="电话"> | |||
<nut-input v-model="staff.staff.phone" class="nut-input-text" type="number" /> | |||
</nut-form-item> | |||
</nut-form> | |||
</template> |
@@ -200,7 +200,7 @@ const onSaveAndSendMessage = () => { | |||
</view> | |||
<view class="pl-3 pr-3 pt-2 pb-2"> | |||
<nut-button :disabled="contactData.phone.length !== 11 || contactData.isBlock" block type="info" @tap="onSaveAndSendMessage">保存并发送邀约短信</nut-button> | |||
<nut-button :disabled="!(contactData.phone) || contactData.phone.length !== 11 || contactData.isBlock" block type="info" @tap="onSaveAndSendMessage">保存并发送邀约短信</nut-button> | |||
</view> | |||
<view class="pl-3 pr-3 pt-2 pb-2"> | |||
@@ -2,5 +2,8 @@ export default definePageConfig({ | |||
navigationBarTitleText: '', | |||
usingComponents: {}, | |||
navigationStyle: 'custom', | |||
disableScroll: true | |||
disableScroll: true, | |||
enablePullDownRefresh: true,//开启页面下拉刷新 | |||
backgroundTextStyle: 'dark'//设置下拉刷新的三个点,默认白色 | |||
}) |
@@ -1,16 +1,10 @@ | |||
<script lang="ts" setup> | |||
import Contact from "../../components/contact" | |||
import { Router } from 'tarojs-router-next' | |||
import {reactive, ref} from 'vue'; | |||
import {registerRouterBackListener, Router} from 'tarojs-router-next' | |||
import {reactive} from 'vue'; | |||
import './index.scss' | |||
import { useContactsStore, ContactData } from '../../stores/contacts' | |||
import { registerRouterBackListener } from 'tarojs-router-next' | |||
import {gql} from "graphql-tag"; | |||
import {PinyinHelper, GQLRequest, weappAuth} from "../../utils"; | |||
import {useAuthStore} from "../../stores/auth"; | |||
import {ContactData, useContactsStore} from '../../stores/contacts' | |||
import {weappAuth} from "../../utils"; | |||
// defineExpose({ | |||
// loadContactsFromServer, | |||
@@ -0,0 +1,6 @@ | |||
export default definePageConfig({ | |||
navigationBarTitleText: '', | |||
usingComponents: {}, | |||
navigationStyle: 'custom', | |||
disableScroll: true | |||
}) |
@@ -0,0 +1,20 @@ | |||
page { | |||
height: 100%; | |||
} | |||
.nut-navbar { | |||
background: transparent; | |||
} | |||
.scroll { | |||
flex: 1; | |||
overflow: scroll; | |||
} | |||
.save-button { | |||
font-size: 36px | |||
} | |||
.nut-action-sheet__item { | |||
color: red !important; | |||
} |
@@ -0,0 +1,90 @@ | |||
<script setup lang="ts"> | |||
import {Router} from 'tarojs-router-next' | |||
import './index.scss' | |||
import Taro from "@tarojs/taro"; | |||
import {Session} from "../../utils"; | |||
import {useStaffItemStore} from "../../stores/my-info"; | |||
const staffData = Router.getData() | |||
const staff = useStaffItemStore() | |||
const myData = Session.get("staff") | |||
console.log(myData); | |||
staff.setStaff(myData) | |||
const goBack = () => { | |||
Router.back() | |||
} | |||
const onSaveClicked = () => { | |||
console.log(staffData); | |||
if (myData.name === ""){ | |||
Taro.showToast({ | |||
title: '名字不能为空', | |||
icon: 'none', | |||
duration: 2000}) | |||
return | |||
} | |||
Taro.showLoading({ | |||
title: 'loading', | |||
}) | |||
console.log("onSaveClicked") | |||
console.log(staff.staff) | |||
staff.updateStaff().then(r => { | |||
console.log("updateStaff", r) | |||
}).catch(error => { | |||
Taro.hideLoading() | |||
if (error) { | |||
const errorMessage = (typeof error === "string")? error : "服务器错误,请稍后重试" | |||
Taro.showToast({ | |||
title: errorMessage, | |||
icon: 'none', | |||
duration: 2000 | |||
}) | |||
} | |||
else { | |||
Taro.showToast({ | |||
title: '网络异常,请稍后重试', | |||
icon: 'none', | |||
duration: 2000 | |||
}) | |||
} | |||
console.log("error", error) | |||
}) | |||
} | |||
</script> | |||
<template> | |||
<view class="h-100 d-flex flex-column"> | |||
<BackgroundBasic/> | |||
<NutNavbar title=""></NutNavbar> | |||
<view class="p-3 d-flex"> | |||
<view class="flex-grow-1"> | |||
<view class="h3"> | |||
<view class="fas fa-chevron-left text-primary" @tap="goBack()" hover-class="btn-hover-primary"/> | |||
更新个人信息 | |||
</view> | |||
<view class="text-black-50"></view> | |||
</view> | |||
<view class="d-flex align-items-end pt-3"> | |||
<view class="text-primary save-button pt-3" hover-class="btn-hover-primary" @tap="onSaveClicked()">保存</view> | |||
</view> | |||
</view> | |||
<view class="scroll"> | |||
<MyInfoForm :data="staffData"/> | |||
</view> | |||
</view> | |||
</template> |
@@ -35,6 +35,10 @@ function init() { | |||
}) | |||
} | |||
const onAvatarClick = () => { | |||
Router.toMyInfo(Session.get("staff")) | |||
} | |||
const onAuthErrorRefresh = () => { | |||
init() | |||
} | |||
@@ -71,6 +75,10 @@ const onAboutUsClicked = () => { | |||
} | |||
const goToMyInfoEditPage = (item) => { | |||
Router.toMyInfoEdit({ data: item }) | |||
} | |||
</script> | |||
<template> | |||
@@ -104,8 +112,8 @@ const onAboutUsClicked = () => { | |||
</view> | |||
<View v-else class="w-100" style="overflow-x: hidden"> | |||
<View class="d-flex justify-content-center pt-5 pb-3"> | |||
<NutAvatar size="large" class="overflow-hidden"> | |||
<img :src="Session.get('staff').avatar" /> | |||
<NutAvatar size="large" class="overflow-hidden" @click="onAvatarClick"> | |||
<img :src="Session.get('staff').avatar" alt=""/> | |||
</NutAvatar> | |||
</View> | |||
<View class="text-center h4"> | |||
@@ -1,9 +1,6 @@ | |||
<script setup> | |||
import {Component} from 'react' | |||
import Taro,{ Current } from '@tarojs/taro' | |||
import './index.scss' | |||
import {Session} from "../../utils"; | |||
import {Router, NavigateType} from "tarojs-router-next"; | |||
import {Router} from "tarojs-router-next"; | |||
import {View} from "@tarojs/components"; | |||
const params = Router.getParams() | |||
@@ -0,0 +1,137 @@ | |||
// https://pinia.esm.dev/introduction.html | |||
import {defineStore} from 'pinia' | |||
import {GQLRequest, Session} from "../utils"; | |||
import {gql} from "graphql-tag"; | |||
import {ref, Ref, UnwrapRef} from "vue"; | |||
import Taro from "@tarojs/taro"; | |||
export const useStaffItemStore = defineStore('my-info', () => { | |||
interface Staff { | |||
id?: number | |||
userName: string | |||
userType: number | |||
nickName: string | |||
avatar: string | |||
phone: string | |||
sex: string | |||
deptId: string | |||
resourceId: number | |||
delFlag: number | |||
} | |||
const staff: Ref<UnwrapRef<Staff>> = ref(getEmptyStaffData()) | |||
const staffNewAvatar: Ref<UnwrapRef<string>> = ref("") | |||
function setStaff(staffItem: Staff) { | |||
staff.value = staffItem | |||
console.log("setContact", staff.value) | |||
} | |||
function setNewAvatar(avatar: string) { | |||
staffNewAvatar.value = avatar | |||
} | |||
function getEmptyStaffData(): Staff { | |||
return { | |||
id: undefined, | |||
userName: "", | |||
userType: undefined, | |||
nickName: "", | |||
avatar: "", | |||
phone: "", | |||
sex: "", | |||
deptId: "", | |||
resourceId: undefined, | |||
delFlag: 0 | |||
} | |||
} | |||
const UPDATE_STAFF = gql` | |||
mutation UpdateStaff($staffId: ID!, $id: ID!, $userName: String!, $nickName: String, $phone: String, $resourceId: ID ) { | |||
updateStaff( staffId: $staffId, input: { | |||
id: $id, | |||
userName: $userName, | |||
nickname: $nickName, | |||
phone: $phone, | |||
resourceId: $resourceId | |||
} ) { | |||
id | |||
} | |||
} | |||
` | |||
const DELETE_VISITOR = gql` | |||
mutation DeleteStaff($id: ID! ) { | |||
deleteStaff( id: $id ) | |||
} | |||
` | |||
function updateStaff() { | |||
const id = staff.value.id | |||
const userName = staff.value.userName | |||
const nickName = staff.value.nickName | |||
const phone = staff.value.phone | |||
return new Promise((resolve, reject) => { | |||
if (staffNewAvatar.value !== "") { | |||
uploadFace().then(r => { | |||
console.log(r) | |||
const resourceId = r.data.resourceId | |||
GQLRequest.query(UPDATE_STAFF, { id, userName, nickName, phone, resourceId }) | |||
.then(r=> { | |||
// contact.value.id = r.data.updateStaff.id | |||
resolve(r) | |||
}) | |||
.catch(e=> reject(e)) | |||
}).catch(e => { | |||
reject(e.msg) | |||
}) | |||
} | |||
else { | |||
GQLRequest.query(UPDATE_STAFF, {id, userName, nickName, phone }) | |||
.then(r=> { | |||
// contact.value.id = r.data.updateStaff.id | |||
resolve(r) | |||
}) | |||
.catch(e=> reject(e)) | |||
} | |||
}) | |||
} | |||
function deleteStaff() { | |||
const id = staff.value.id | |||
const staffId = Session.get("staff").id | |||
return GQLRequest.query(DELETE_VISITOR, { staffId, id }) | |||
} | |||
function uploadFace() { | |||
return new Promise((resolve, reject) => { | |||
console.log("aaaaaaaa", staffNewAvatar.value) | |||
Taro.uploadFile({ | |||
url: SERVER_URL + '/system/resources/upload-face', | |||
header: { | |||
Authorization: 'Bearer ' + Session.get('access_token'), | |||
}, | |||
name: "file", | |||
filePath: staffNewAvatar.value, | |||
success: result => { | |||
const data = JSON.parse(result.data) | |||
if (result.statusCode == 200 && data.code !== 500) resolve(data) | |||
else reject(data) | |||
}, | |||
fail: res => { | |||
reject(res) | |||
} | |||
}) | |||
}) | |||
} | |||
return { staff, setStaff, updateStaff, deleteStaff, getEmptyStaffData, setNewAvatar } | |||
}) |