From 895ddb867609c07bd728a96bb194fc1443354300 Mon Sep 17 00:00:00 2001 From: HardenSG <2767525216@qq.com> Date: Tue, 14 May 2024 01:52:01 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E6=9B=B4=E6=96=B0=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E5=9F=8B=E7=82=B9=E4=B8=8A=E6=8A=A5=E5=B1=9E=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit refactor: 组织初始化 & 课程选择 feat: 调试backend接口 feat: 新增我的页面 --- src/app.tsx | 29 +- src/common-model.ts | 27 +- .../baseBuiltComp/HocWrap/index.tsx | 10 +- src/components/common/InputMenu/index.tsx | 33 +- src/components/common/InputMenu/types.ts | 4 +- src/components/common/VirtualList/types.ts | 14 +- src/config.ts | 8 +- src/model/index.tsx | 3 + src/model/runtime-model.ts | 41 ++ src/model/system-model.ts | 31 ++ src/model/userinfo-model.ts | 26 ++ src/models.ts | 10 +- src/pages/Detail/components/Poster.tsx | 10 +- src/pages/Detail/index.tsx | 27 +- src/pages/Initial/common.ts | 30 +- .../Initial/components/grade.module.scss | 5 +- src/pages/Initial/components/gradeInit.tsx | 365 +++++++++++++++--- .../Initial/components/initAccomplish.tsx | 106 ++++- src/pages/Initial/components/orgInit.tsx | 205 +++++----- src/pages/Initial/index.tsx | 191 +++++---- src/pages/Initial/types.ts | 10 +- src/pages/Setting/Course/common.ts | 9 +- src/pages/Setting/Course/index.module.scss | 8 + src/pages/Setting/Course/index.tsx | 155 ++++++-- src/pages/Setting/Course/types.ts | 6 +- src/pages/Setting/index.config.ts | 2 +- src/pages/Setting/index.module.scss | 3 +- src/pages/Setting/index.tsx | 2 +- src/pages/main/Index/common.ts | 11 +- .../Index/components/Tasklist/task-filter.tsx | 20 +- .../Index/components/Tasklist/task-item.tsx | 16 +- .../Index/components/Tasklist/task-list.tsx | 12 +- src/pages/main/Index/index.tsx | 109 +----- src/pages/main/Index/types.ts | 14 +- .../components/feedback.modules.scss | 1 + .../Manage/components/work-manage/index.tsx | 2 +- src/pages/main/Manage/index.module.scss | 1 + src/pages/main/My/index.config.ts | 5 +- src/pages/main/My/index.module.scss | 72 +++- src/pages/main/My/index.tsx | 102 ++++- src/static/SVG/lottie-map.ts | 1 + src/static/tabbarIcon/home.png | Bin 3960 -> 1004 bytes src/static/tabbarIcon/home_active.png | Bin 3980 -> 1415 bytes src/static/tabbarIcon/manage.png | Bin 12720 -> 1157 bytes src/static/tabbarIcon/manage_active.png | Bin 12754 -> 1349 bytes src/static/tabbarIcon/my.png | Bin 7000 -> 847 bytes src/static/tabbarIcon/my_active.png | Bin 7053 -> 1008 bytes src/types/business/student.ts | 4 +- src/types/entity/task.ts | 8 +- src/types/entity/work.ts | 2 + src/types/index copy.ts | 3 - src/utils/perfTrack/business.ts | 19 +- src/utils/request/business.ts | 16 +- src/utils/request/constants.ts | 6 +- src/utils/route/goTo.ts | 2 +- src/utils/storage.ts | 5 +- src/utils/subscribe.ts | 31 +- 57 files changed, 1276 insertions(+), 556 deletions(-) create mode 100644 src/model/index.tsx create mode 100644 src/model/runtime-model.ts create mode 100644 src/model/system-model.ts create mode 100644 src/model/userinfo-model.ts delete mode 100644 src/types/index copy.ts diff --git a/src/app.tsx b/src/app.tsx index f643a79..988a1e7 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -1,22 +1,23 @@ import { Provider } from 'react-redux' import Taro, { useError, useLaunch } from '@tarojs/taro' import Error from 'src/components/baseBuiltComp/Error' -import { IStudentStruct, TBizStudentGetInfo, omit, setStorage } from 'src/utils' +import { IStudentStruct, TBizStudentGetInfo } from 'src/utils' import { store } from './store' import './app.scss' import { Get, getStorage, preloadResource, requestUrlCreator, trackJsError } from './utils' import { JSON_MAP } from './static/SVG/lottie-map' -const filterRules = /node/ +const filterRules = /evaluating 'n\[0\]\.node'|Cannot read property 'node' of null/ function App(props) { useError((err) => { - console.log('错了', err) if (!filterRules.test(err)) { + console.log('错了', err) + trackJsError({ token: getStorage('userInfo')?.token ?? 'no_login', errMsg: err.toString(), location: '全局错误捕捉 ===> ' + err.toString(), - errName: 'global_err_catch', + err_name: 'global_err_catch', }) } return @@ -31,20 +32,13 @@ function App(props) { let userinfo: IStudentStruct | null = null if (token) { try { - const res = await Get({ + const { isSuccess, data } = await Get({ url: requestUrlCreator({ rootPath: 'WX_STU', absolutePath: '/getStudent' }), silent: true, }) - if (res.isSuccess) { - const { - data: { studentVo }, - } = res - userinfo = { - ...studentVo, - } - store.dispatch.common.update_UserInfo({ - ...userinfo /** TODO: 更新响应体结构 */, - }) + if (isSuccess) { + userinfo = data.studentVo + store.dispatch.userinfoModel.update_UserInfo(userinfo) } } catch (err) { console.log(' === 获取用户信息请求错误 === ', err) @@ -61,10 +55,11 @@ function App(props) { fail: console.log, }) - store.dispatch.common.update_SystemInfo({ + const { classId = 0, collegeId = 0, gradeId = 0 } = userinfo || {} + store.dispatch.systemModel.update_SystemInfo({ sessionStatus: !token ? 'fail' : 'ok', coldStartSuccess: true, - hasAccountCompleted: !!(userinfo || false) /** TODO: 是否具备完整信息需要再确认下 */, + hasAccountCompleted: collegeId > 0 && gradeId > 0 && classId > 0, }) console.log('==== 应用冷启动初始化成功! ====') }) diff --git a/src/common-model.ts b/src/common-model.ts index 1d40e17..9b635c1 100644 --- a/src/common-model.ts +++ b/src/common-model.ts @@ -6,7 +6,8 @@ import { getStorage, setStorage } from './utils/storage' export interface IUserInfo { token?: string username?: string - userActor?: string + avatarUrl?: string + wechatId?: string /** 是否绑定授权码 */ isBindManage?: boolean /** 所属组织 */ @@ -14,6 +15,30 @@ export interface IUserInfo { orgName?: string gradeId?: number gradeName?: string + classId?: number + className?: string + organization?: { + collegeId: string + gradeId: string + classId: string + } + organizationVo?: { + classVo?: { + gradeId: string + id: number + name: string + } + college?: { + id: number + logoUrl: string + name: string + } + grade?: { + collegeId: string + id: number + name: string + } + } } /** 系统运行所需全局缓存 */ diff --git a/src/components/baseBuiltComp/HocWrap/index.tsx b/src/components/baseBuiltComp/HocWrap/index.tsx index 2404a30..d78858f 100644 --- a/src/components/baseBuiltComp/HocWrap/index.tsx +++ b/src/components/baseBuiltComp/HocWrap/index.tsx @@ -10,7 +10,8 @@ import Guide from './components/guideInit' /** @HOC 校验登陆态 */ export const Authorize = (Component) => { return React.memo(() => { - const state = useSelector((root: RootState) => root.common.system) + const state = useSelector((root: RootState) => root.systemModel) + console.log('=== sysState ===', state) if (!state.coldStartSuccess) { return } else { @@ -23,12 +24,13 @@ export const Authorize = (Component) => { /** @HOC 禁止页面要求必须是已授权的 */ export const Forbidden = (Component, props?: any) => { return React.memo(() => { - const state = useSelector((root: RootState) => root.common) + const sysState = useSelector((root: RootState) => root.systemModel) + const userState = useSelector((root: RootState) => root.userinfoModel) /** TODO: 更新字段取值口径 */ - if (!state.system.coldStartSuccess) { + if (!sysState.coldStartSuccess) { return } else { - if (state.userInfo.isBindManage) return + if (userState.isBindManage) return return {props} } }) diff --git a/src/components/common/InputMenu/index.tsx b/src/components/common/InputMenu/index.tsx index e188662..173b495 100644 --- a/src/components/common/InputMenu/index.tsx +++ b/src/components/common/InputMenu/index.tsx @@ -4,6 +4,7 @@ import { View } from '@tarojs/components' import Mask from '../Mask' import './index.module.scss' import VirtialList from '../VirtualList' +import { TInputMenuItem } from './types' interface IInputMenuProps { /** 下拉列表 */ @@ -26,6 +27,8 @@ interface IInputMenuProps { onPageScrollToLower?: () => void /** 输入值改变回调 */ handleInputChange?: (value) => void + /** 输入值改变回调 */ + clickMark?: () => void } const Index = ({ @@ -37,6 +40,7 @@ const Index = ({ inputPlace = '请输入...', onPageScrollToLower, handleInputChange, + clickMark = () => {}, inputStyle, listStyle, }: IInputMenuProps) => { @@ -51,15 +55,18 @@ const Index = ({ console.log('menuLists', menuLists) /** 下拉框数据是否存在 */ - const isCanShowMenu = useMemo(() => menuLists && menuLists.length, [menuLists]) + const isCanShowMenu = useMemo(() => menuLists && menuLists.length != 0, [menuLists]) /** 下拉框显示状态 */ const clickShowMenu = () => { + if (status === true) { + clickMark() + } setStatus(!status) } /** 点击item选项 */ const clickItem = (item) => { - setValue(item) + setValue(item.name) setStatus(false) handleInputChange?.(item) } @@ -74,11 +81,14 @@ const Index = ({ // const total = 15 /** 渲染列表Item */ - const renderFunc = (item, index, pageIndex) => { + const renderFunc = (item: TInputMenuItem, index, pageIndex) => { return ( - clickItem(item.Value)}> + clickItem({ name: item.name, id: item.id })} + > - {`${item.Value}`} + {`${item.name}`} ) } @@ -97,7 +107,7 @@ const Index = ({ alignItems: 'center', }} > - 没有更多了 + 没啦没啦,真的没有了~ ) } @@ -186,16 +196,7 @@ const Index = ({ ) : ( /** 下拉框数据不存在 */ - - 暂无数据 - + 暂无数据 ) } diff --git a/src/components/common/InputMenu/types.ts b/src/components/common/InputMenu/types.ts index 9e96cc3..f302848 100644 --- a/src/components/common/InputMenu/types.ts +++ b/src/components/common/InputMenu/types.ts @@ -1,7 +1,7 @@ /** 输入下拉菜单列表的类型 */ export type TInputMenuItem = { - Id: number - Value: string + id: number + name: string } /** 任务列表的类型 */ diff --git a/src/components/common/VirtualList/types.ts b/src/components/common/VirtualList/types.ts index ff1f2f5..f8f3364 100644 --- a/src/components/common/VirtualList/types.ts +++ b/src/components/common/VirtualList/types.ts @@ -1,13 +1,13 @@ import { CSSProperties, ComponentClass } from 'react' -/** 输入下拉菜单列表的类型 */ -export type TInputMenuItem = { - Id: number - Value: string -} +// /** 输入下拉菜单列表的类型 */ +// export type TInputMenuItem = { +// id: number +// name: string +// } -/** 任务列表的类型 */ -export type TInputMenuList = TInputMenuItem[] +// /** 任务列表的类型 */ +// export type TInputMenuList = TInputMenuItem[] export interface BaseComponent { className?: string diff --git a/src/config.ts b/src/config.ts index b875790..025b385 100644 --- a/src/config.ts +++ b/src/config.ts @@ -55,14 +55,14 @@ export const config: Config = { { pagePath: 'pages/main/Manage/index', text: '', - iconPath: './static/tabbarIcon/my.png', - selectedIconPath: './static/tabbarIcon/my_active.png', + iconPath: './static/tabbarIcon/manage.png', + selectedIconPath: './static/tabbarIcon/manage_active.png', }, { pagePath: 'pages/main/My/index', text: '', - iconPath: './static/tabbarIcon/manage.png', - selectedIconPath: './static/tabbarIcon/manage_active.png', + iconPath: './static/tabbarIcon/my.png', + selectedIconPath: './static/tabbarIcon/my_active.png', }, ], }, diff --git a/src/model/index.tsx b/src/model/index.tsx new file mode 100644 index 0000000..6fcfd92 --- /dev/null +++ b/src/model/index.tsx @@ -0,0 +1,3 @@ +export * from './runtime-model' +export * from './system-model' +export * from './userinfo-model' diff --git a/src/model/runtime-model.ts b/src/model/runtime-model.ts new file mode 100644 index 0000000..5c0e9a7 --- /dev/null +++ b/src/model/runtime-model.ts @@ -0,0 +1,41 @@ +import { createModel } from '@rematch/core' +import { RootModel } from 'src/models' +import { getStorage, setStorage } from '../utils/storage' + +type TOrganizationCache = { + /** 所属组织 */ + orgId?: number + orgName?: string + gradeId?: number + gradeName?: string + classId?: number + className?: string + courseIds?: number[] +} +/** 系统运行所需全局缓存 */ +export interface IRuntimeCache { + organizationCache: TOrganizationCache +} + +/** 默认store值 从storage中激活 */ +export const defaultRuntimeValue: IRuntimeCache = { + organizationCache: getStorage('runtimeCache').organizationCache || {}, +} + +export const runtimeModel = createModel()({ + state: defaultRuntimeValue, + reducers: { + writeOrgCache( + state: IRuntimeCache, + newCache: Partial, + needLasting?: boolean, + ) { + state.organizationCache = newCache + state.organizationCache = Object.assign({}, state.organizationCache, newCache) + if (needLasting) { + setStorage('runtimeCache', state) + } + return state + }, + }, +}) diff --git a/src/model/system-model.ts b/src/model/system-model.ts new file mode 100644 index 0000000..586f927 --- /dev/null +++ b/src/model/system-model.ts @@ -0,0 +1,31 @@ +import { createModel } from '@rematch/core' +import { RootModel } from 'src/models' + +/** 系统运行所需全局缓存 */ +export interface ISystemInfo { + /** session状态 */ + sessionStatus?: string + /** 冷启动初始化是否完成 */ + coldStartSuccess?: boolean + /** 是否完善用户信息 */ + hasAccountCompleted?: boolean + /** 是否弹过授权弹窗 */ + isAuthorizeSubscribePop?: boolean +} + +/** 默认store值 从storage中激活 */ +export const defaultSystemValue: ISystemInfo = { + coldStartSuccess: false, + hasAccountCompleted: false, + isAuthorizeSubscribePop: false, +} + +export const systemModel = createModel()({ + state: defaultSystemValue, + reducers: { + update_SystemInfo: (state: ISystemInfo, newSystemInfo: Partial) => { + state = Object.assign({}, state, newSystemInfo) + return state + }, + }, +}) diff --git a/src/model/userinfo-model.ts b/src/model/userinfo-model.ts new file mode 100644 index 0000000..dbb88c2 --- /dev/null +++ b/src/model/userinfo-model.ts @@ -0,0 +1,26 @@ +import { createModel } from '@rematch/core' +import { RootModel } from 'src/models' +import { IStudentStruct } from 'src/types' +import { getStorage, setStorage } from '../utils/storage' + +/** TODO: 用户信息需要确定好内容 */ +export interface IUserInfo extends IStudentStruct { + /** 鉴权 */ + token?: string +} + +/** 默认store值 从storage中激活 */ +export const defaultUserinfoValue: Partial = { + ...(getStorage('userInfo') || {}), +} + +export const userinfoModel = createModel()({ + state: defaultUserinfoValue, + reducers: { + update_UserInfo: (state: IUserInfo, newUserinfo: Partial) => { + state = Object.assign({}, state, newUserinfo) + setStorage('userInfo', state) + return state + }, + }, +}) diff --git a/src/models.ts b/src/models.ts index b649456..7550ffc 100644 --- a/src/models.ts +++ b/src/models.ts @@ -1,10 +1,14 @@ import { Models } from '@rematch/core' -import { common } from './common-model' +import { userinfoModel, systemModel, runtimeModel } from './model' export interface RootModel extends Models { - common: typeof common + userinfoModel: typeof userinfoModel + systemModel: typeof systemModel + runtimeModel: typeof runtimeModel } export const models: RootModel = { - common, + userinfoModel, + systemModel, + runtimeModel, } diff --git a/src/pages/Detail/components/Poster.tsx b/src/pages/Detail/components/Poster.tsx index 453fe72..874551f 100644 --- a/src/pages/Detail/components/Poster.tsx +++ b/src/pages/Detail/components/Poster.tsx @@ -3,10 +3,10 @@ import { pxTransform } from '@tarojs/taro' import { PosterRender, PosterRenderRef } from '@poster-render/taro-react' import { View } from '@tarojs/components' import Button from '@taroify/core/button/button' -import { TTaskItem, getStorage, showToast, trackJsError } from 'src/utils' +import { IWork, getStorage, showToast, trackJsError } from 'src/utils' import './poster.scss' -const lists = (data: TTaskItem) => [ +const lists = (data: IWork) => [ { type: 'image', x: 0, @@ -39,7 +39,7 @@ const lists = (data: TTaskItem) => [ lineNum: 15, width: 372, height: 22, - text: data.desc, + text: data.description, color: 'black', fontSize: 22, lineHeight: 30, @@ -47,7 +47,7 @@ const lists = (data: TTaskItem) => [ ] type TPosterProps = { - posterData: TTaskItem + posterData: IWork } const Index: FC = ({ posterData }) => { const posterRender = useRef(null) @@ -67,7 +67,7 @@ const Index: FC = ({ posterData }) => { trackJsError({ token: getStorage('userInfo').token || 'no_login', errMsg: err, - errName: type, + err_name: type, location: 'detail/poster', }) }, []) diff --git a/src/pages/Detail/index.tsx b/src/pages/Detail/index.tsx index 8b6423b..15fa26c 100644 --- a/src/pages/Detail/index.tsx +++ b/src/pages/Detail/index.tsx @@ -1,7 +1,8 @@ import { View, Text, Image } from '@tarojs/components' -import React, { FC, useCallback, useState } from 'react' +import React, { FC, useCallback, useMemo, useState } from 'react' import Taro, { useShareAppMessage } from '@tarojs/taro' import { + IWork, Post, TTaskItem, getCurrentPage, @@ -18,17 +19,15 @@ import './index.module.scss' import Poster from './components/Poster' const Index: FC = () => { - const { data, loading, err } = useRequest( + const { data, loading, err } = useRequest( () => ({ - url: requestUrlCreator({ absolutePath: '/detail' }), + url: requestUrlCreator({ rootPath: 'WX_WORK', absolutePath: `/${query()?.id}` }), type: 'Get', - reqData: { - id: query()?.id, - }, silent: true, }), { auto: true }, ) + const imgs = useMemo(() => data?.pictureLinks?.split(',').map((v) => v) || [], [data]) const [isShowPoster, setIsShowPoster] = useState(false) const updateTaskStatus = useCallback(() => { @@ -70,7 +69,7 @@ const Index: FC = () => { 作业详情 - + {/* {data!.tags?.map((tag) => { return ( @@ -78,33 +77,33 @@ const Index: FC = () => { ) })} - + */} {data?.title} 截止日期: - {timeFormat(data?.time, 'YYYY年MM月DD日 hh:mm:ss')} + {timeFormat(data?.deadline, 'YYYY年MM月DD日 hh:mm:ss')} 发布人: - {data?.publisher} + {data?.publisherId || '暂时没有发布人'} 内容: {'\n'}        - {data?.desc} + {data?.description} <> - {(data!.imgs || []).map((img) => { + {imgs.map((img) => { return ( { Taro.previewImage({ current: img, - urls: [...(data?.imgs || [])], + urls: [...imgs], }) }} key={1} @@ -138,7 +137,7 @@ const Index: FC = () => { {isShowPoster && ( - + setIsShowPoster(false)}> ❌ diff --git a/src/pages/Initial/common.ts b/src/pages/Initial/common.ts index 9b4fece..730ca79 100644 --- a/src/pages/Initial/common.ts +++ b/src/pages/Initial/common.ts @@ -2,10 +2,38 @@ import { requestUrlCreator } from 'src/utils' /** 组织数据的基础路径 */ export const organizationInterUrl = requestUrlCreator({ - absolutePath: '/organization' /** TODO: 需要替换,mock路径 */, + absolutePath: '/collegePage' /** TODO: 需要替换,mock路径 */, + rootPath: 'WX_ORG', }) /** 登录路径 */ export const loginInterUrl = requestUrlCreator({ absolutePath: '/getToken', }) + +/** 学生信息的基础路径 */ +export const getStudentInfoUrl = requestUrlCreator({ + absolutePath: '/getStudent', +}) + +/** token检查路径 */ +export const checkTokenUrl = requestUrlCreator({ + absolutePath: '/checkToken', +}) + +/** 更新学生信息基础路径 */ +export const updateStudentInfoUrl = requestUrlCreator({ + absolutePath: '/update', +}) + +/** 年级数据的基础路径 */ +export const gradeInterUrl = requestUrlCreator({ + absolutePath: '/gradePage' /** TODO: 需要替换,mock路径 */, + rootPath: 'WX_ORG', +}) + +/** 班级数据的基础路径 */ +export const classInterUrl = requestUrlCreator({ + absolutePath: '/classPage' /** TODO: 需要替换,mock路径 */, + rootPath: 'WX_ORG', +}) diff --git a/src/pages/Initial/components/grade.module.scss b/src/pages/Initial/components/grade.module.scss index 6cfbc82..3cdb754 100644 --- a/src/pages/Initial/components/grade.module.scss +++ b/src/pages/Initial/components/grade.module.scss @@ -1,8 +1,8 @@ @import '../../../app.scss'; .grade__content { - padding-top: 210rpx; - font-size: 36px; + padding-top: 190rpx; + font-size: 24px; display: flex; flex-direction: column; align-items: center; @@ -11,6 +11,7 @@ height: 100vh; &__title { + font-size: 30px; color: $text-color-primary; margin-bottom: 15rpx; width: 580rpx; diff --git a/src/pages/Initial/components/gradeInit.tsx b/src/pages/Initial/components/gradeInit.tsx index 8e018a3..4e5ab52 100644 --- a/src/pages/Initial/components/gradeInit.tsx +++ b/src/pages/Initial/components/gradeInit.tsx @@ -1,104 +1,341 @@ import { View } from '@tarojs/components' -import React, { useCallback, useRef, useState } from 'react' +import React, { useCallback, useEffect, useState } from 'react' import InputMenu from 'src/components/common/InputMenu' -import { goTo, query, URL } from 'src/utils' +import { getStorage, isObj, Post, showToast } from 'src/utils' +import { TInputMenuList } from 'src/components/common/InputMenu/types' +import useUpdateEffect from 'src/hooks/useUpdateEffect' import { Button, Image } from '@taroify/core' import { useSelector } from 'react-redux' import { RootState, store } from 'src/store' import './grade.module.scss' +import { classInterUrl, gradeInterUrl } from '../common' +import { TOrgList } from '../types' + +/** 每页个数 */ +const SIZE = 4 as const const Index = () => { /** 年级列表 */ - const [gradeList, setGradeList] = useState([{ Id: 1, Value: '年级' }]) + const [gradeList, setGradeList] = useState([]) /** 班级列表 */ - const [classList, setClassList] = useState([{ Id: 1, Value: '班' }]) - const inputValue = useRef('') - // const num = useRef(1) - const onPageScrollToLower = () => { - console.log('页面触底了') - if (pageNum.current >= total.current) return - console.log('num', pageNum.current) - - pageNum.current++ - segmentNum.current = 20 - total.current = 1 - } - const handleInputChange = (value) => { - console.log('handleInputChange-', value) - } + const [classList, setClassList] = useState([]) /** 分页当前页数 */ - const pageNum = useRef(1) + const [gPageNum, setGPageNum] = useState(1) /** 总页数 */ - const total = useRef(1) - /** 每页个数 */ - const segmentNum = useRef(20) - - // 缓存年级班级信息 - const dispatch = useSelector(() => store.dispatch.common) - const state = useSelector((root: RootState) => root.common) - const goToPage = useCallback(() => { - // 存在 - dispatch.update_SystemInfo({ - ...state.system, - isAuthorizeSubscribePop: true, - hasAccountCompleted: true, + const [gPagesTotal, setGPagesTotal] = useState(1) + + /** 分页当前页数 */ + const [cPageNum, setCPageNum] = useState(1) + /** 总页数 */ + const [cPagesTotal, setCPagesTotal] = useState(1) + + /** 搜索年级内容 */ + const [inputGradeValue, setInputGradeValue] = useState<{ id?: number; name: string }>() + /** 搜索班级内容 */ + const [inputClassValue, setInputClassValue] = useState<{ id?: number; name: string }>() + + // 缓存组织信息 + const orgCacheDispatch = useSelector(() => store.dispatch.runtimeModel) + const orgCacheState = useSelector((root: RootState) => root.runtimeModel.organizationCache) + + /** =============================================================== */ + + // 年级列表请求 + const reqGradeFn = useCallback( + ({ currentPage, size = SIZE, keyword = '', collegeId }) => + Post({ + url: gradeInterUrl, + data: { + page: currentPage, + size, + keyword, + collegeId, + }, + silent: true, + }) + .then((res) => { + const { isSuccess, errMsg, code, extraData, data } = res + + if (!isSuccess || !data) { + throw Error(errMsg) + } + return { + data, + extraData, + } + }) + .catch((err) => { + showToast(err) + }), + [], + ) + + // 班级列表请求 + const reqClassFn = useCallback( + ({ currentPage, size = SIZE, keyword = '', gradeId }) => + Post({ + url: classInterUrl, + data: { + page: currentPage, + size, + keyword, + gradeId, + }, + silent: true, + }) + .then((res) => { + const { isSuccess, errMsg, extraData, data } = res + if (!isSuccess || !data) { + throw Error(errMsg) + } + return { + data, + extraData, + } + }) + .catch((err) => { + showToast(err) + }), + [], + ) + + //首次请求 初始化年级和班级 + useEffect(() => { + if (orgCacheState?.gradeId) { + orgCacheDispatch.writeOrgCache({ + ...orgCacheState, + gradeId: undefined, + gradeName: undefined, + }) + } + /* mounted */ + reqGradeFn({ currentPage: 1, collegeId: orgCacheState.orgId }).then((res) => { + if (!res) return + const { data, extraData } = res + setGradeList(data) + setGPagesTotal(extraData!.pages) }) - dispatch.update_UserInfo({ ...state.userInfo, gradeId: 1, gradeName: '1' }) - console.log('state', store.getState().common.system) - // goTo({ - // url: URL.Index, - // methodType: 'switchTab', - // extraParams: { - // ...query(), - // }, - // options: { - // authorize: false, - // }, - // }) }, []) + //初始化班级 + useEffect(() => { + /* mounted */ + if (orgCacheState?.gradeId) { + reqClassFn({ currentPage: 1, gradeId: orgCacheState.gradeId }).then((res) => { + if (!res) return + const { data, extraData } = res + setClassList(data) + setCPagesTotal(extraData!.pages) + }) + } + }, [orgCacheState.gradeId]) + + useUpdateEffect(() => { + reqGradeFn({ + currentPage: gPageNum, + keyword: inputGradeValue?.name, + collegeId: orgCacheState.orgId, + }).then((res) => { + console.log('当前页:', gPageNum, '搜索内容:', inputGradeValue) + if (!res) return + setGradeList([...gradeList, ...res!.data]) + setGPagesTotal(res!.extraData!.pages) + }) + }, [gPageNum, inputGradeValue?.name]) + + useUpdateEffect(() => { + reqClassFn({ + currentPage: cPageNum, + keyword: inputClassValue?.name, + gradeId: orgCacheState.gradeId, + }).then((res) => { + console.log('当前页:', cPageNum, '搜索内容:', inputClassValue) + if (!res) return + setClassList([...classList, ...res!.data]) + setCPagesTotal(res!.extraData!.pages) + }) + }, [cPageNum, inputClassValue?.name]) + + const onGradePageScrollToLower = () => { + if (gPageNum < gPagesTotal) { + // 未超出设置 页数加一 + setGPageNum(gPageNum + 1) + } + } + + const onClassPageScrollToLower = () => { + if (cPageNum < cPagesTotal) { + // 未超出设置 页数加一 + setCPagesTotal(cPageNum + 1) + } + } + + const handleGradeInputChange = (value) => { + if (orgCacheState?.gradeId) { + orgCacheDispatch.writeOrgCache({ + ...orgCacheState, + gradeId: undefined, + gradeName: undefined, + classId: undefined, + className: undefined, + }) + } + setGradeList([]) + if (isObj(value)) { + setInputGradeValue(value) + } else { + setInputGradeValue({ name: value }) + } + setGPageNum(1) + } + + const handleClassInputChange = (value) => { + if (orgCacheState?.classId) { + orgCacheDispatch.writeOrgCache({ + ...orgCacheState, + classId: undefined, + className: undefined, + }) + } + setClassList([]) + if (isObj(value)) { + setInputClassValue(value) + } else { + setInputClassValue({ name: value }) + } + setCPageNum(1) + } + + /** 点击遮罩 page置1 */ + const clickMarkGrade = () => { + //如果当前页不为1初始化组织列表 + if (gPageNum != 1) { + setGradeList([]) + setGPageNum(1) + } + if (gradeList.length === 0 && gPageNum === 1 && inputGradeValue?.name.length === 0) { + reqGradeFn({ currentPage: 1, collegeId: orgCacheState.orgId }).then((res) => { + if (!res) return + const { data, extraData } = res + setGradeList(data) + setGPagesTotal(extraData!.pages) + }) + } + } + + /** 点击遮罩 page置1 */ + const clickMarkClass = () => { + //如果当前页不为1初始化组织列表 + if (cPageNum != 1) { + setClassList([]) + setCPageNum(1) + } + if (classList.length === 0 && cPageNum === 1 && inputClassValue?.name.length === 0) { + reqClassFn({ currentPage: 1, gradeId: orgCacheState.gradeId }).then((res) => { + if (!res) return + const { data, extraData } = res + setClassList(data) + setCPagesTotal(extraData!.pages) + }) + } + } + + const checkGradeToClass = useCallback(() => { + if (!inputGradeValue?.id || !inputGradeValue?.name) { + showToast({ title: '错啦,请重新选择!', icon: 'error' }) + return + } + // 存在 + orgCacheDispatch.writeOrgCache({ + ...orgCacheState, + gradeId: inputGradeValue.id, + gradeName: inputGradeValue.name, + }) + }, [inputGradeValue]) + + const checkClass = useCallback(() => { + if (!inputClassValue?.id || !inputClassValue?.name) { + showToast({ title: '错啦,请重新选择!', icon: 'error' }) + return + } + // 存在 + orgCacheDispatch.writeOrgCache({ + ...orgCacheState, + classId: inputClassValue.id, + className: inputClassValue.name, + }) + }, [inputClassValue]) + + // 点击下一步 + const checkGradeAndClass = () => { + if (!inputGradeValue?.name) { + showToast({ title: '请选择年级!', icon: 'error' }) + return + } + + checkGradeToClass() + + if (!inputClassValue?.name && orgCacheState?.gradeId) { + showToast({ title: '请选择班级!', icon: 'error' }) + return + } + + if (inputClassValue?.name && orgCacheState?.gradeId) { + checkClass() + } + } + return ( <> 加入一个年级、班级吧 - - - + + {orgCacheState?.gradeId ? ( + <> + + + + + ) : ( + <> + )} diff --git a/src/pages/Initial/components/initAccomplish.tsx b/src/pages/Initial/components/initAccomplish.tsx index 7ac7d04..bfe92da 100644 --- a/src/pages/Initial/components/initAccomplish.tsx +++ b/src/pages/Initial/components/initAccomplish.tsx @@ -1,18 +1,68 @@ import { Canvas, View } from '@tarojs/components' -import React, { useCallback } from 'react' +import React, { useCallback, useEffect, useState } from 'react' import { Button } from '@taroify/core' -import { $, goTo, query, URL } from 'src/utils' +import { $, getStorage, goTo, IBaseStudentStruct, Post, query, showToast, URL } from 'src/utils' import useAnimation from 'src/hooks/useAnimation' import { JSON_MAP } from 'src/static/SVG/lottie-map' +import { useSelector } from 'react-redux' +import { RootState, store } from 'src/store' +import { updateStudentInfoUrl } from '../common' import './initAccomplish.module.scss' const Index = () => { - useAnimation({ + const orgCacheState = useSelector((root: RootState) => root.runtimeModel.organizationCache) + const orgCacheDispatch = useSelector(() => store.dispatch.runtimeModel) + const sysDispatch = useSelector(() => store.dispatch.systemModel) + const { run } = useAnimation({ node: $('#InitAccomplish__bgContainer__canvas'), template: JSON_MAP['initial_success'], _options: { loop: false }, }) - const goToPage = useCallback(() => { + + const [updateSuccess, setUpdateSuccess] = useState(false) + + // 更新学生信息请求 + const reqUpdateFn = useCallback( + () => + Post({ + url: updateStudentInfoUrl, + data: { + classId: orgCacheState.classId, + collegeId: orgCacheState.orgId, + gradeId: orgCacheState.gradeId, + // nickname: 'string', + studentId: '0', + wechatId: getStorage('userInfo').wechatId, + }, + silent: true, + }).then((res) => { + const { isSuccess, errMsg, code } = res + if (!isSuccess || code != 0) { + throw Error(errMsg) + } + setUpdateSuccess(true) + }), + [], + ) + + useEffect(() => { + reqUpdateFn() + }, []) + + useEffect(() => { + if (updateSuccess) { + run() + } + }, [updateSuccess]) + + const reselect = useCallback(() => { + // reqUpdateFn() + // 清除组织缓存 重新填写 + orgCacheDispatch.writeOrgCache({}) + }, []) + + const goToPage = () => { + sysDispatch.update_SystemInfo({ hasAccountCompleted: true }) goTo({ url: URL.SettingCourse, methodType: 'reLaunch', @@ -23,25 +73,41 @@ const Index = () => { authorize: false, }, }) - }, []) + } return ( - {/* 完成 */} - - + {!updateSuccess ? ( + + 哎呦错啦, +
+ +
+ ) : ( + <> + + + + )}
) } diff --git a/src/pages/Initial/components/orgInit.tsx b/src/pages/Initial/components/orgInit.tsx index 97aa025..440665c 100644 --- a/src/pages/Initial/components/orgInit.tsx +++ b/src/pages/Initial/components/orgInit.tsx @@ -1,137 +1,127 @@ import { View } from '@tarojs/components' -import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react' -import { URL, goTo, query } from 'src/utils' -import { Button, Cell, Field, Input } from '@taroify/core' -import { TInputMenuList, TInputMenuItem } from 'src/components/common/InputMenu/types' +import React, { useCallback, useEffect, useState } from 'react' +import { Post, getStorage, isObj, showToast, trackAPIError } from 'src/utils' +import { Button } from '@taroify/core' +import { TInputMenuList } from 'src/components/common/InputMenu/types' import InputMenu from 'src/components/common/InputMenu' -import useRequest from 'src/hooks/useRequest' import { RootState, store } from 'src/store' import { useSelector } from 'react-redux' +import useUpdateEffect from 'src/hooks/useUpdateEffect' import { TOrgList } from '../types' import { organizationInterUrl } from '../common' import './org.module.scss' +/** 每页个数 */ +const SIZE = 4 as const + const Index = () => { const [orgList, setOrgList] = useState([]) - const { data, run } = useRequest( - () => ({ - type: 'Get', - reqData: {}, - url: organizationInterUrl, - silent: true, - }), - { auto: true }, + /** 分页当前页数 */ + const [pageNum, setPageNum] = useState(1) + /** 总页数 */ + const [pagesTotal, setPagesTotal] = useState(1) + /** 搜索内容 */ + const [inputValue, setInputValue] = useState<{ id?: number; name: string }>() + const userState = useSelector((root: RootState) => root.userinfoModel) + + const reqFn = useCallback( + ({ currentPage, size = SIZE, keyword = '' }) => + Post({ + url: organizationInterUrl, + data: { + page: currentPage, + size, + keyword, + }, + loadingNeedMask: true, + }) + .then((res) => { + const { isSuccess, errMsg, extraData, data } = res + + if (!isSuccess || !data) { + throw Error(errMsg) + } + return { + data, + extraData, + } + }) + .catch((err) => { + showToast(err) + }), + [], ) useEffect(() => { - const list: TInputMenuList = [] - data?.forEach((v) => { - const item = {} as TInputMenuItem - item.Id = v.orgId - item.Value = v.orgName - list.push(item) + /* mounted */ + // TODO: 优化此处的多次请求 + if (!userState?.token) return + reqFn({ currentPage: 1 }).then((res) => { + if (!res) return + const { data, extraData } = res + setOrgList(data) + setPagesTotal(extraData!.pages) }) - setOrgList(list) - }, [data]) + }, [userState]) - const goToPage = useCallback(() => { - goTo({ - url: URL.Initial, - methodType: 'redirectTo', - extraParams: { - ...query(), - }, - options: { - authorize: false, - }, + useUpdateEffect(() => { + reqFn({ currentPage: pageNum, keyword: inputValue?.name }).then((res) => { + console.log('当前页:', pageNum, '搜索内容:', inputValue) + if (!res) return + setOrgList([...orgList, ...res!.data]) + setPagesTotal(res!.extraData!.pages) }) - }, []) + }, [pageNum, inputValue?.name]) - const inputValue = useRef('') - // const num = useRef(1) const onPageScrollToLower = () => { - console.log('页面触底了') - if (pageNum.current >= total.current) return - console.log('当前页数:', pageNum.current) - - pageNum.current++ - segmentNum.current = 20 - total.current = 5 - - const lists: TInputMenuList = [] - data?.forEach((v) => { - const item = {} as TInputMenuItem - item.Id = v.orgId - item.Value = v.orgName - lists.push(item) - }) - setOrgList([...(orgList as []), ...(lists as [])]) + if (pageNum < pagesTotal) { + // 未超出设置 页数加一 + setPageNum(pageNum + 1) + } } const handleInputChange = (value) => { - console.log('handleInputChange =', value) - inputValue.current = value - if (Object.keys(value).length > 0) { - findOrganization(value) + setOrgList([]) + if (isObj(value)) { + setInputValue(value) } else { - //初始化 - segmentNum.current = 20 - pageNum.current = 1 - total.current = 5 - const lists: TInputMenuList = [] - data?.forEach((v) => { - const item = {} as TInputMenuItem - item.Id = v.orgId - item.Value = v.orgName - lists.push(item) - }) - setOrgList([...(lists as [])]) + setInputValue({ name: value }) } + setPageNum(1) } - // const findOrganization = useCallback(() => { - // run() - // }, [run]) - const findOrganization = (value) => { - const res = [ - { - Id: 1, - Value: '搜索的组织: ' + value, - }, - { - Id: 2, - Value: '搜索的组织2', - }, - ] - for (let i = 3; i < 30; i++) { - res.push({ - Id: i, - Value: '搜索的组织' + i, + + /** 点击遮罩 page置1 */ + const clickMark = () => { + //如果当前页不为1初始化组织列表 + if (pageNum != 1) { + setOrgList([]) + setPageNum(1) + } + if (orgList.length === 0 && pageNum === 1 && inputValue?.name.length === 0) { + reqFn({ currentPage: 1 }).then((res) => { + if (!res) return + const { data, extraData } = res + setOrgList(data) + setPagesTotal(extraData!.pages) }) } - setOrgList(res) - pageNum.current = 1 - // segmentNum.current = res.length - total.current = 2 } - /** 分页当前页数 */ - // const pageTotal = useMemo(() => { - // return orgList.length / 20 - // }, [orgList]) - const pageNum = useRef(1) - /** 总页数 */ - const total = useRef(5) - /** 每页个数 */ - const segmentNum = useRef(20) - // 缓存组织信息 - const dispatch = useSelector(() => store.dispatch.common) - const state = useSelector((root: RootState) => root.common) + const orgCacheDispatch = useSelector(() => store.dispatch.runtimeModel) + const orgCacheState = useSelector((root: RootState) => root.runtimeModel.organizationCache) + const checkOrgToGrade = useCallback(() => { - console.log('检查组织是否存在') + if (!inputValue?.id || !inputValue?.name) { + showToast({ title: '错啦,请重新选择!', icon: 'error' }) + return + } // 存在 - dispatch.update_UserInfo({ ...state.userInfo, orgId: 1, orgName: inputValue.current }) - console.log('state', store.getState().common.userInfo) - }, []) + orgCacheDispatch.writeOrgCache({ + ...orgCacheState, + orgId: inputValue.id, + orgName: inputValue.name, + }) + }, [inputValue]) return ( @@ -152,10 +142,11 @@ const Index = () => { diff --git a/src/pages/Initial/index.tsx b/src/pages/Initial/index.tsx index 50a956b..531c89f 100644 --- a/src/pages/Initial/index.tsx +++ b/src/pages/Initial/index.tsx @@ -1,118 +1,171 @@ -import { Button, View } from '@tarojs/components' import Taro from '@tarojs/taro' -import React, { useCallback } from 'react' +import React, { useCallback, useEffect, useMemo, useState } from 'react' import { useSelector } from 'react-redux' -import { IUserInfo } from 'src/common-model' -import usePerfTrack from 'src/hooks/usePerfTrack' -import useRequest from 'src/hooks/useRequest' import { RootState, store } from 'src/store' import { getStorage, goTo, isTabBarPage, query, - requestUrlCreator, showToast, - trackAPIError, + Get, + TBizStudentGetInfo, } from 'src/utils' -import request from 'src/utils/request' +import useUpdateEffect from 'src/hooks/useUpdateEffect' import OrgInit from './components/orgInit' -import { loginInterUrl } from './common' +import { getStudentInfoUrl, loginInterUrl } from './common' import GradeInit from './components/gradeInit' import InitAccomplish from './components/initAccomplish' const Index = () => { - console.log(' === 到达 === ', query()) const url = query()?.$fromPage as string - const dispatch = useSelector(() => store.dispatch.common) - const state = useSelector((root: RootState) => root.common) + const userDispatch = useSelector(() => store.dispatch.userinfoModel) + const sysDispatch = useSelector(() => store.dispatch.systemModel) + const orgCacheDispatch = useSelector(() => store.dispatch.runtimeModel) + const userState = useSelector((root: RootState) => root.userinfoModel) + const orgCacheState = useSelector((root: RootState) => root.runtimeModel.organizationCache) + const [isLogin, setLogin] = useState() + /** 用户信息 拿到token 组织 年级 班级 */ + // TODO: 这个地方有问题 + const { + orgId: _orgId, + orgName: _orgName, + gradeId: _gradeId, + gradeName: _gradeName, + classId: _classId, + className: _className, + } = orgCacheState + let hasOrg = useMemo(() => !!(_orgId && _orgName), [_orgId, _orgName]) + let hasGrade = useMemo(() => !!(_gradeId && _gradeName), [_gradeId, _gradeName]) + let hasClass = useMemo(() => !!(_classId && _className), [_classId, _className]) + + // 完善,全量参数透传跳转到目标页面 + const back = useCallback(() => { + /** 完善信息 */ + sysDispatch.update_SystemInfo({ sessionStatus: 'ok', hasAccountCompleted: true }) + /** 判断上一页是否为tabbar */ + const methodType = isTabBarPage(url) ? 'switchTab' : 'redirectTo' + /** 返回上一页 */ + goTo({ url, methodType, extraParams: { ...query() } }) + }, [url]) const toLogin = () => { Taro.login({ success: async function (res) { if (res.code) { console.log(' === wx登陆成功 === ', res.code) - /** 业务登录请求 */ - const result: any = await request['Post']({ + const result = await Get({ url: loginInterUrl, data: { code: res.code }, - silent: false, + silent: true, }) /** 校验是否成功 */ if (result.isSuccess) { /** 请求完成 */ - console.log('请求结果:', result.data) - // setStorage('userInfo', { token: result.data.token }) - dispatch.update_UserInfo({ ...state.userInfo, token: result.data.token }) - dispatch.update_SystemInfo({ - ...state.system, - sessionStatus: 'ok', - }) - console.log('token =', getStorage('userInfo').token) - console.log('state', store.getState().common.userInfo.token) + userDispatch.update_UserInfo({ token: result.data }) + sysDispatch.update_SystemInfo({ sessionStatus: 'ok' }) + setLogin(true) + } else { + result.handleException() } } else { + // TODO: 错误处理 showToast({ title: '登录失败', icon: 'error' }) + throw Error(`获取微信code失败code: {${res.errMsg}}`) } }, - fail: function () { + fail(err) { + // TODO: 错误处理 showToast({ title: '微信登录失败', icon: 'error' }) + throw Error(`请求微信登录失败: {${err.errMsg}}`) }, }) } - /** 用户信息 拿到token 组织 年级 班级 */ - const { orgId, orgName, gradeId, gradeName } = store.getState().common.userInfo - let hasOrg = useCallback(() => !!(orgId && orgName), [orgId, orgName]) - let hasGrade = useCallback(() => !!(gradeId && gradeName), [gradeId, gradeName]) - - // 检查本地存储有无token - if (!!getStorage('userInfo').token) { - // 有token,判断微信登录态是否过期 - Taro.checkSession({ - success: function () { - //session_key 未过期,并且在本生命周期一直有效 - console.log(' === session_key 未过期 === ') - // dispatch.update_SystemInfo({ - // ...state.system, - // sessionStatus: 'ok', - // }) - }, - fail: function () { - // session_key 已经失效,需要重新执行登录流程 - // 过期,拉起微信登录,重新登录 - toLogin() - }, + const getStudentInfo = async () => { + // 有token获取用户信息 + const result = await Get({ + url: getStudentInfoUrl, + loadingNeedMask: true, + silent: true, }) - } else { - // 无token,拉起微信登录 - toLogin() + const { code, data } = result + console.log('我请求了!!', result) + + if (code || !data?.studentVo) { + //清除token + userDispatch.update_UserInfo({ token: undefined }) + return { errno: 1, msg: '用户信息获取失败', data } + } + return { errno: 0, data } } - // 未过期,请求用户信息,有无组织,年级,班级,头像昵称,课程信息 + const saveUserCourses = async ({ courseVos }: TBizStudentGetInfo) => { + // 存课程ID + if (courseVos && !orgCacheState.courseIds) { + const courseIds = courseVos.map((i: { id: any }) => i.id) + orgCacheDispatch.writeOrgCache({ courseIds }) + } + return { errno: 0 } + } - // 未完善,跳转到初始化页面 + /** 保存用户相关信息 */ + const saveUserinfo = async ({ studentVo, organizationVo }: TBizStudentGetInfo) => { + const { classId, collegeId, gradeId, nickname, avatarUrl, wechatId } = studentVo + // 如果有组织信息,存本地,透传跳转到目标页面 + if (organizationVo) { + // 有组织信息存本地 + userDispatch.update_UserInfo({ classId, collegeId, gradeId }) + //全量透传跳转 + return { errno: 0, action: 'back' } + } - // 完善,全量参数透传跳转到目标页面 - const back = useCallback(() => { - /** 完善信息 */ - dispatch.update_SystemInfo({ ...state.system, sessionStatus: 'ok', hasAccountCompleted: true }) - /** 判断上一页是否为tabbar */ - const methodType = isTabBarPage(url) ? 'switchTab' : 'redirectTo' - /** 返回上一页 */ - goTo({ url, methodType, extraParams: { ...query() } }) - }, [dispatch, state.system, url]) + //如果无组织信息,存基本信息,本地有基本信息,直接返回 + const { + nickname: lNickname, + avatarUrl: lAvatarUrl, + wechatId: lWechatId, + } = getStorage('userInfo') + if (lNickname && lAvatarUrl && lWechatId) return { errno: 0, action: '' } + userDispatch.update_UserInfo({ nickname, avatarUrl, wechatId }) + return { errno: 0, action: '' } + } + + useEffect(() => { + const token = getStorage('userInfo')?.token + setLogin(!!token as any) + }, []) + + useUpdateEffect(() => { + ;(async () => { + if (isLogin) { + const { errno, msg, data } = await getStudentInfo() + if (errno) return showToast(msg) // TODO: 失败处理 :retry + + /** 存储用户相关状态 */ + await saveUserCourses(data) + await saveUserinfo(data).then(({ action }) => { + const eventMap = { back } + const fn = eventMap[action] + fn && fn() + }) + /** END */ + + if (userState?.collegeId || 0 > 0) back() + } else { + toLogin() + } + })() + }, [isLogin]) - return ( - - {!hasOrg() && } - {hasOrg() && !hasGrade() && } - {hasOrg() && hasGrade() && } - {/* */} - - ) + // 未完善,跳转到组织初始化页面 + const notHaveOrg = !hasOrg + const onlyHasOrg = hasOrg && !hasGrade + if (notHaveOrg) return + if (onlyHasOrg || !hasClass) return + return } export default React.memo(Index) diff --git a/src/pages/Initial/types.ts b/src/pages/Initial/types.ts index aad51db..8f3efbd 100644 --- a/src/pages/Initial/types.ts +++ b/src/pages/Initial/types.ts @@ -1,9 +1,13 @@ +import { TInputMenuItem } from '../../components/common/InputMenu/types' + /** 组织的类型 */ -export type TOrgItem = { +export interface TOrgItem extends TInputMenuItem { /** 当前组织ID */ - orgId: number + // id: number /** 当前组织ID */ - orgName: string + // name: string + /** 组织logourl */ + logoUrl: string } /** 任务列表的类型 */ diff --git a/src/pages/Setting/Course/common.ts b/src/pages/Setting/Course/common.ts index 7612ea0..423a4a8 100644 --- a/src/pages/Setting/Course/common.ts +++ b/src/pages/Setting/Course/common.ts @@ -9,5 +9,12 @@ export const IndexContextProvider = createContext({ /** 课程数据的基础路径 */ export const getCourseInterUrl = requestUrlCreator({ - absolutePath: '/course' /** TODO: 需要替换,mock路径 */, + absolutePath: '/coursePage' /** TODO: 需要替换,mock路径 */, + rootPath: 'WX_ORG', +}) + +/** 提交课程的基础路径 */ +export const saveCoursesInterUrl = requestUrlCreator({ + absolutePath: '/saveCourses' /** TODO: 需要替换,mock路径 */, + rootPath: 'WX_WORK', }) diff --git a/src/pages/Setting/Course/index.module.scss b/src/pages/Setting/Course/index.module.scss index a6d3c63..9a94eac 100644 --- a/src/pages/Setting/Course/index.module.scss +++ b/src/pages/Setting/Course/index.module.scss @@ -13,4 +13,12 @@ width: 500rpx; color: #000; } + &__noData { + display: flex; + align-items: center; + justify-content: center; + height: 80vh; + margin: 17px; + color: gray; + } } diff --git a/src/pages/Setting/Course/index.tsx b/src/pages/Setting/Course/index.tsx index 3dec459..0abf0e6 100644 --- a/src/pages/Setting/Course/index.tsx +++ b/src/pages/Setting/Course/index.tsx @@ -1,77 +1,160 @@ import { View } from '@tarojs/components' -import React, { useEffect, useState } from 'react' -import useRequest from 'src/hooks/useRequest' -import { Button, Cell, Checkbox } from '@taroify/core' -import { goTo, query, URL } from 'src/utils' +import React, { useCallback, useEffect, useState } from 'react' +import { Button, Cell, Checkbox, Dialog } from '@taroify/core' +import { getStorage, goTo, Post, query, URL } from 'src/utils' +import { useSelector } from 'react-redux' +import { RootState } from 'src/store' import CourseSearch from './components/course-search' -import { getCourseInterUrl } from './common' +import { getCourseInterUrl, saveCoursesInterUrl } from './common' import { TCoueseList } from './types' import './index.module.scss' const Index = () => { - /** 透传:列表项 */ + /** 课程列表项 */ const [courseLists, setCourseLists] = useState([]) + + /** 已选课程ID */ + const [selectCourses, setSelectCourses] = useState([]) + + /** 本学院下课程总数 */ + const [countTotal, setCountTotal] = useState(10) + /** 透传:当前页数 */ const [page, setPage] = useState(0) /** 透传:搜索的文字 */ const [searchText, setSearchText] = useState('') - /** 透传:请求能力 */ - const { data, loading, run } = useRequest( - () => ({ - type: 'Get', - url: getCourseInterUrl, - silent: true, - reqData: {}, - }), - { auto: true }, + const [open, setOpen] = useState(false) + + const orgCacheState = useSelector((root: RootState) => root.runtimeModel.organizationCache) + + // 更新学生信息请求 + const reqUpdateFn = useCallback( + (size: number = 10) => + Post({ + url: getCourseInterUrl, + data: { size }, + silent: false, + }).then((res) => { + const { errMsg, code, extraData, data } = res + + if (code != 0 || !extraData) { + throw Error(errMsg) + } + + return { + data, + extraData, + } + }), + [], ) /** 请求初始化数据 */ useEffect(() => { - console.log('ddd', data) - setCourseLists(data) - // run().then((res) => { - // console.log(res) - // }) - }, [data]) + reqUpdateFn() + .then((res) => { + if (res?.extraData?.count) { + reqUpdateFn(res?.extraData?.count).then((result) => [ + setCourseLists(result?.data as TCoueseList), + ]) + } + }) + .catch((err) => { + console.log('== 课程获取失败 ==', err) + }) + + setSelectCourses(orgCacheState.courseIds as never[]) + }, []) + + /** 请求初始化数据 */ + useEffect(() => { + console.log(selectCourses) + }, [selectCourses]) /** 提交课程 */ const submitCourse = () => { console.log('提交课程') - - // 跳转回首页 - goTo({ - url: URL.Index, - methodType: 'switchTab', - extraParams: { - ...query(), - }, - options: { - authorize: false, + console.log(selectCourses) + Post({ + url: saveCoursesInterUrl, + data: { + courseIds: selectCourses, + studentId: getStorage('userInfo')?.wechatId /** TODO: 需要更换为wechatid */, }, + silent: false, + }).then((res) => { + const { errMsg, code } = res + + if (code != 0) { + throw Error(errMsg) + } + console.log() + + setOpen(true) }) + + // 跳转回首页 + // goTo({ + // url: URL.Index, + // methodType: 'switchTab', + // extraParams: { + // ...query(), + // }, + // options: { + // authorize: false, + // }, + // }) } /** 全选 */ const selectAll = () => { + const list = courseLists.map((i) => i.id) + setSelectCourses(list as never[]) console.log('全选') } + const onChangeCheck = (id: any) => { + setSelectCourses(id) + } + return ( + + 选课完成 + 是否继续选课,还是跳转回主页! + + + + + - {!courseLists ? ( - 暂时没有课程~ + {courseLists.length === 0 ? ( + 暂时没有课程~ ) : ( - + {courseLists.map((item) => { return ( - - + + ) })} diff --git a/src/pages/Setting/Course/types.ts b/src/pages/Setting/Course/types.ts index 155892a..2e59825 100644 --- a/src/pages/Setting/Course/types.ts +++ b/src/pages/Setting/Course/types.ts @@ -46,6 +46,8 @@ export type TCoueseList = TCourseItem[] /** 课程的类型 */ export type TCourseItem = { - courseId: string - courseName: string + collegeId: number + id: number + name: string + teacherId: number } diff --git a/src/pages/Setting/index.config.ts b/src/pages/Setting/index.config.ts index ecbd470..30f2e24 100644 --- a/src/pages/Setting/index.config.ts +++ b/src/pages/Setting/index.config.ts @@ -4,7 +4,7 @@ export default definePageConfig({ /** 是否开启下拉刷新 */ enablePullDownRefresh: false, /** 自定义导航栏 */ - navigationStyle: 'custom', + navigationStyle: 'default', /** 自定义背景颜色 */ backgroundColor: '#ffffff', }) diff --git a/src/pages/Setting/index.module.scss b/src/pages/Setting/index.module.scss index 1dd5430..4cd9fc5 100644 --- a/src/pages/Setting/index.module.scss +++ b/src/pages/Setting/index.module.scss @@ -1,3 +1,4 @@ +@import '../../app.scss'; .list { display: flex; flex-direction: column; @@ -13,6 +14,6 @@ width: 500rpx; height: 80rpx; margin: 10rpx; - background-color: aqua; + background-color: $primary-color; } } diff --git a/src/pages/Setting/index.tsx b/src/pages/Setting/index.tsx index 2a499a5..31fad7a 100644 --- a/src/pages/Setting/index.tsx +++ b/src/pages/Setting/index.tsx @@ -24,7 +24,7 @@ const targetPage = [ const Index = () => { return ( - goTo({ methodType: 'navigateBack' })}>设置页面 + {/* goTo({ methodType: 'navigateBack' })}>设置页面 */} {targetPage.map((v) => { return ( diff --git a/src/pages/main/Index/common.ts b/src/pages/main/Index/common.ts index 759e3f3..b8247af 100644 --- a/src/pages/main/Index/common.ts +++ b/src/pages/main/Index/common.ts @@ -9,7 +9,8 @@ export const IndexContextProvider = createContext({ /** 列表数据的基础路径 */ export const getListInterUrl = requestUrlCreator({ - absolutePath: '/lists' /** TODO: 需要替换,mock路径 */, + rootPath: 'WX_WORK', + absolutePath: '/searchWorks', }) /** 任务数据基础路径 */ @@ -17,14 +18,6 @@ export const taskInterUrl = requestUrlCreator({ absolutePath: '/tasks', }) -/** 需要被订阅的模版 */ -export const tplIds = [ - /** 作业提醒 */ - 'X4et8qrCY9UA3yXAB1FfZ16UXOU4-2wglppSqYxTAII', - /** 消息通知 */ - 'V8JzyKTZZ16srBpi1QQMMUDCLMYzutIVvWGy8irgxiM', -] - /** 任务状态枚举 */ export const TASK_STATUS = { /** 有效期内 */ diff --git a/src/pages/main/Index/components/Tasklist/task-filter.tsx b/src/pages/main/Index/components/Tasklist/task-filter.tsx index 0b3bfeb..9f4cfc0 100644 --- a/src/pages/main/Index/components/Tasklist/task-filter.tsx +++ b/src/pages/main/Index/components/Tasklist/task-filter.tsx @@ -1,5 +1,5 @@ import { View, Text } from '@tarojs/components' -import React, { useState, Key, useContext, useEffect } from 'react' +import React, { useState, Key, useContext } from 'react' import { Descending } from '@taroify/icons' import { DropdownMenu } from '@taroify/core' import { TFilterType } from '../../types' @@ -23,10 +23,10 @@ const Index = ({ /** 匹配文字 */ const mapFilterTypeText = (val: TFilterType) => { const map = { - all: '全部', - un_expired: '未完成', - resolve: '已完成', - timeout: '已过期', + 100: '全部', + 0: '未完成', + 1: '已读', + 2: '已完成', } return map[val] } @@ -35,7 +35,7 @@ const Index = ({ 当前查看类型: - {mapFilterTypeText(filterType || 'all')} + {mapFilterTypeText(filterType ?? 100)} 请选择你想查看的筛选类型 - 全部 - 未完成 - 已完成 - 已过期 + 全部 + 未完成 + 已读 + 已完成 diff --git a/src/pages/main/Index/components/Tasklist/task-item.tsx b/src/pages/main/Index/components/Tasklist/task-item.tsx index cb0f68b..12a893b 100644 --- a/src/pages/main/Index/components/Tasklist/task-item.tsx +++ b/src/pages/main/Index/components/Tasklist/task-item.tsx @@ -1,8 +1,8 @@ import { View, Text } from '@tarojs/components' import React from 'react' -import { Delete, Put, TTaskItem, URL, goTo, subscribeHOF, timeFormat } from 'src/utils' +import { Delete, Put, URL, goTo, subscribeHOF, timeFormat, tplIds } from 'src/utils' import { SwipeCell } from '@taroify/core' -import { TGeneralObject } from 'src/types' +import { IWork, TGeneralObject } from 'src/types' import type { SwipeCellProps } from '@taroify/core/swipe-cell/swipe-cell' import { ArrowDown as ArrowDownIcon, @@ -11,7 +11,7 @@ import { Exchange as ExchangeIcon, } from '@taroify/icons' import { TPropsThrough } from '../../types' -import { IndexContextProvider, TASK_STATUS, taskInterUrl, tplIds } from '../../common' +import { IndexContextProvider, TASK_STATUS, taskInterUrl } from '../../common' import './item.module.scss' /** 任务状态枚举 */ @@ -62,9 +62,9 @@ const formatDesc = (str: string) => (str.length > 30 ? str.substring(0, 30) : st /** Props类型限制 */ type TTaskItemProps = { /** 渲染细则 */ - taskInfo: TTaskItem + taskInfo: IWork /** 父传子触发事件 */ - handleEvents: (events: 'delete' | 'resolve' | 'reopen', taskinfo: TTaskItem) => void + handleEvents: (events: 'delete' | 'resolve' | 'reopen', taskinfo: IWork) => void } /** state类型限制 */ @@ -184,7 +184,7 @@ class Index extends React.PureComponent { } render() { - const { time, title, desc } = this.props.taskInfo + const { deadline, title, description } = this.props.taskInfo const { openDire } = this.state return ( { {title} - 截止日期:{timeFormat(time, 'YYYY年MM月DD日 hh:mm:ss')} + 截止日期:{timeFormat(deadline, 'YYYY年MM月DD日 hh:mm:ss')} - 简介:{formatDesc(desc)} + 简介:{formatDesc(description)} diff --git a/src/pages/main/Index/components/Tasklist/task-list.tsx b/src/pages/main/Index/components/Tasklist/task-list.tsx index 10a2ed4..ef7743b 100644 --- a/src/pages/main/Index/components/Tasklist/task-list.tsx +++ b/src/pages/main/Index/components/Tasklist/task-list.tsx @@ -1,7 +1,7 @@ -import { Button, View } from '@tarojs/components' +import { View } from '@tarojs/components' import React, { FC, useCallback, useContext, useMemo, useState } from 'react' import { Divider, Empty, List, PullRefresh } from '@taroify/core' -import { TTaskItem } from 'src/utils' +import { IWork } from 'src/utils' import TaskItem from './task-item' import { TStateHookUpdateFn, TTaskList } from '../../types' import { IndexContextProvider } from '../../common' @@ -60,7 +60,7 @@ const Index: FC<{ lists: TTaskList; setPage: TStateHookUpdateFn }> = ({ * *这里只做ui级别的承接,实际上删除、重启、完成仍然依赖接口* */ const handleTaskItemEvents = useCallback( - async (events: 'delete' | 'resolve' | 'reopen', taskinfo: TTaskItem) => { + async (events: 'delete' | 'resolve' | 'reopen', taskinfo: IWork) => { const index = lists.findIndex((v) => v.id === taskinfo.id) /** TODO: 求最优解。当前在长列表的背景下会容易卡顿。尝试虚拟列表? */ /** 因为不能直接修改lists,react会判定引用没有变化即使使用setState也不会变化 */ @@ -80,7 +80,8 @@ const Index: FC<{ lists: TTaskList; setPage: TStateHookUpdateFn }> = ({ case 'reopen': { copiedList.splice(index, 1) /** 如果是默认筛选模式 => 删完之后插到第一个 */ - if (filterType === 'all') { + // TODO: 新增枚举 + if (filterType === 100) { copiedList.unshift(taskinfo) } } @@ -129,7 +130,8 @@ const Index: FC<{ lists: TTaskList; setPage: TStateHookUpdateFn }> = ({ ) : ( /* 用来兜底用户删了过多元素,从而无法触发触底的case */ - + // + <> )} ) : ( diff --git a/src/pages/main/Index/index.tsx b/src/pages/main/Index/index.tsx index 14f1171..888fe4d 100644 --- a/src/pages/main/Index/index.tsx +++ b/src/pages/main/Index/index.tsx @@ -1,83 +1,3 @@ -// import { View, Text } from '@tarojs/components' -// import React, { useCallback, useEffect, useState } from 'react' -// import useRequest from 'src/hooks/useRequest' -// import Loading from 'src/components/baseBuiltComp/Loading' -// import { Authorize } from 'src/components/baseBuiltComp/HocWrap' -// import TaskList from './components/Tasklist/task-list' -// import TaskFilter from './components/Tasklist/task-filter' -// import TaskSearch from './components/Tasklist/task-search' -// import { TFilterType, TTaskList } from './types' -// import { IndexContextProvider, getListInterUrl } from './common' -// import './index.module.scss' - -// const Index = () => { -// /** 列表项 */ -// const [lists, setList] = useState() -// /** 筛选规则 */ -// const [filterType, setFilterType /** TODO: 透传给筛选组件 */] = useState('all') -// const { data, loading, run } = useRequest(() => ({ -// type: 'Get', -// url: getListInterUrl, -// silent: true, -// reqData: { -// /** TODO: 需要更新名字 */ -// filterType, -// /** TODO: 页面 */ -// page: 0 -// }, -// })) -// useEffect(() => { -// setList(data) -// }, [data]) - -// /** 透传自组件更新列表数据 */ -// const updateList = useCallback((list: TTaskList) => { -// setList(list) -// }, []) - -// useEffect(() => { -// console.log(' === 筛选类型变化,即将请求 === ') -// run({ filterType, page: 0 }) -// }, [filterType]) - -// // useEffect(() => { -// // showModal({ -// // title: '监测到您还没有订阅', -// // content: '您需要订阅' -// // }).then(res => { -// // subscribe({ -// // tplId: ['V8JzyKTZZ16srBpi1QQMMUDCLMYzutIVvWGy8irgxiM'] -// // }) -// // }) -// // }, []) - -// return ( -// -// -// -// -// -// -// 作业列表 -// -// {/** 用来加筛选 */} -// -// -// -// {loading ? : } -// -// -// -// ) -// } - -// export default React.memo(Index) - import { View, Text } from '@tarojs/components' import React, { useCallback, useEffect, useState } from 'react' import useRequest from 'src/hooks/useRequest' @@ -95,32 +15,31 @@ const Index = () => { /** 透传:列表项 */ const [lists, setList] = useState() /** 透传:筛选规则 */ - const [filterType, setFilterType /** TODO: 透传给筛选组件 */] = useState('all') + const [filterType, setFilterType /** TODO: 透传给筛选组件 */] = useState(100) /** 透传:当前页数 */ const [page, setPage] = useState(0) /** 透传:搜索的文字 */ const [searchText, setSearchText] = useState('') /** 透传:请求能力 */ const { loading, run } = useRequest( - () => ({ - type: 'Get', - url: getListInterUrl, - silent: true, - reqData: { - /** TODO: 需要更新名字 */ - filterType, - /** TODO: 页数 */ + () => { + const baseReqData = { + keyword: searchText, page, - /** TODO: 筛选文字 */ - searchText, - }, - }), + size: 10, + } + return { + type: 'Post', + url: getListInterUrl, + silent: true, + reqData: Object.assign({}, baseReqData, filterType !== 100 ? { status: filterType } : {}), + } + }, { auto: false, deps: [filterType, page, searchText] }, ) /** mounted请求初始化数据 */ useEffect(() => { - // setList(data) run().then((res) => { setList(res) }) @@ -128,7 +47,7 @@ const Index = () => { /** 透传至组件更新列表数据 */ const updateList = useCallback((list: TTaskList) => { - setList(list) + setList(list.filter((v) => v)) }, []) useUpdateEffect(() => { diff --git a/src/pages/main/Index/types.ts b/src/pages/main/Index/types.ts index 04fcc7c..0b72653 100644 --- a/src/pages/main/Index/types.ts +++ b/src/pages/main/Index/types.ts @@ -1,18 +1,18 @@ import React from 'react' import useRequest from 'src/hooks/useRequest' -import { TTaskItem } from 'src/utils' +import { IWork } from 'src/utils' /** 任务列表的类型 */ -export type TTaskList = TTaskItem[] +export type TTaskList = IWork[] /** * 筛选模式 - * - all 不筛选 - * - resolve 已完成 - * - timeout 已过期 - * - un_expired 有效的 + * - 0 unread_unresolve + * - 1 read_unresolve + * - 2 read_resolve + * - 100 all_data */ -export type TFilterType = 'all' | 'resolve' | 'timeout' | 'un_expired' +export type TFilterType = 0 | 1 | 2 | 100 /** 祖先组件provider透传类型定义 */ export type TPropsThrough = { diff --git a/src/pages/main/Manage/components/apply-manage/components/feedback.modules.scss b/src/pages/main/Manage/components/apply-manage/components/feedback.modules.scss index 40427e1..ef00670 100644 --- a/src/pages/main/Manage/components/apply-manage/components/feedback.modules.scss +++ b/src/pages/main/Manage/components/apply-manage/components/feedback.modules.scss @@ -16,6 +16,7 @@ width: 100%; max-height: 95%; overflow-y: scroll; + -webkit-overflow-scrolling: touch; } .list { diff --git a/src/pages/main/Manage/components/work-manage/index.tsx b/src/pages/main/Manage/components/work-manage/index.tsx index f7c06d4..0495e7e 100644 --- a/src/pages/main/Manage/components/work-manage/index.tsx +++ b/src/pages/main/Manage/components/work-manage/index.tsx @@ -1,7 +1,7 @@ import { Button, View } from '@tarojs/components' import React, { useCallback, useEffect, useState } from 'react' import { Forbidden } from 'src/components/baseBuiltComp/HocWrap' -import { Field, Input, Picker, Popup, Textarea, Cell, Watermark } from '@taroify/core' +import { Field, Input, Picker, Popup, Textarea, Cell } from '@taroify/core' import { ArrowRight } from '@taroify/icons' import './index.modules.scss' diff --git a/src/pages/main/Manage/index.module.scss b/src/pages/main/Manage/index.module.scss index 6922089..ce1ff86 100644 --- a/src/pages/main/Manage/index.module.scss +++ b/src/pages/main/Manage/index.module.scss @@ -4,6 +4,7 @@ width: 100vw; height: 100vh; overflow-y: scroll; + -webkit-overflow-scrolling: touch; padding: 0 30rpx 0 30rpx; box-sizing: border-box; diff --git a/src/pages/main/My/index.config.ts b/src/pages/main/My/index.config.ts index a4f647f..0c655b3 100644 --- a/src/pages/main/My/index.config.ts +++ b/src/pages/main/My/index.config.ts @@ -1,10 +1,11 @@ export default definePageConfig({ /** 页面标题 */ - navigationBarTitleText: '我的', + navigationBarTitleText: '', /** 是否开启下拉刷新 */ enablePullDownRefresh: false, /** 自定义导航栏 */ - navigationStyle: 'custom', + navigationStyle: 'default', /** 自定义背景颜色 */ backgroundColor: '#ffffff', + disableScroll: true, }) diff --git a/src/pages/main/My/index.module.scss b/src/pages/main/My/index.module.scss index cb4cafc..a936e02 100644 --- a/src/pages/main/My/index.module.scss +++ b/src/pages/main/My/index.module.scss @@ -1,3 +1,4 @@ +@import '../../../app.scss'; .list { display: flex; flex-direction: column; @@ -15,4 +16,73 @@ margin: 10rpx; background-color: aqua; } -} \ No newline at end of file +} + +.my_wrapper { + display: flex; + flex-direction: column; + width: 100vw; + height: 100vh; + overflow-y: scroll; + -webkit-overflow-scrolling: touch; + padding: 0 30rpx 0 30rpx; + box-sizing: border-box; + + &_title { + display: flex; + justify-content: space-between; + } + &_portrait { + width: 690rpx; + height: 400rpx; + margin: 0 auto; + &__img { + width: 300rpx; + height: 300rpx; + margin: 30rpx auto; + border-radius: 50%; + background-color: $primary-color; + } + } + &_info { + // margin: 0 40rpx; + &__double { + display: flex; + justify-content: space-between; + } + } + &__input { + height: 80rpx; + padding-left: 30rpx; + } +} + +.title__text { + font-size: 45rpx; + // font-weight: normal; + font-family: AlibabaPuHuiTi; +} + +.title__setting { + width: 60rpx; + height: 60rpx; + border-radius: 50%; + margin-right: 22rpx; + background-color: $primary-color; + display: flex; + justify-content: center; + align-items: center; +} + +.title__describe { + margin: 0 auto; + text-align: center; + color: $bg-color-gary5; +} + +.info__text { + font-size: 32rpx; + font-weight: 600; + margin: 10rpx 0; + // font-family: AlibabaPuHuiTi; +} diff --git a/src/pages/main/My/index.tsx b/src/pages/main/My/index.tsx index 8a5a1e7..0b94f62 100644 --- a/src/pages/main/My/index.tsx +++ b/src/pages/main/My/index.tsx @@ -1,18 +1,114 @@ import { View, Text } from '@tarojs/components' -import { URL, goTo } from 'src/utils' +import { SettingOutlined } from '@taroify/icons' +import { Field, Image, Input } from '@taroify/core' +import { useEffect, useState } from 'react' +import { IStudentCollegeInfo, IStudentStruct, URL, goTo, showToast } from 'src/utils' +import { useSelector } from 'react-redux' +import { RootState, store } from 'src/store' +import useRequest from 'src/hooks/useRequest' +import { getStudentInfoUrl } from 'src/pages/Initial/common' import './index.module.scss' const Index = () => { + const [studentOrgInfo, setStudentOrgInfo] = useState({}) + const userState = useSelector((root: RootState) => root.userinfoModel) + const orgCacheDispatch = useSelector(() => store.dispatch.runtimeModel) + const orgCacheState = useSelector((root: RootState) => root.runtimeModel.organizationCache) + + const { run } = useRequest( + () => ({ + type: 'Get', + url: getStudentInfoUrl, + silent: true, + }), + { auto: false }, + ) + + useEffect(() => { + run() + .then((res) => { + const { classVo, college, grade }: IStudentCollegeInfo = res?.organizationVo + + if (!orgCacheState.courseIds) { + const courseIds = res?.courseVos.map((i: any) => i.id) + orgCacheDispatch.writeOrgCache({ courseIds }) + } + + setStudentOrgInfo({ classVo, college, grade }) + }) + .catch(() => { + showToast({ icon: 'error', title: '信息获取失败!' }) + }) + }, []) + return ( - 我的页面 - + {/* 我的页面 */} + {/* goTo({ url: URL.Setting, methodType: 'navigateTo' })} > 去设置 + */} + + + 我的 + goTo({ url: URL.Setting, methodType: 'navigateTo' })} + > + + + + + + + + 昵称: {userState?.nickname} + + + 组织 + + + + + 年级 + + + + 班级 + + + + + + 系统设置 + goTo({ url: URL.Setting, methodType: 'navigateTo' })} + disabled + placeholder='课程选择 / 通知设置 / 意见反馈 / 个性化设置 >' + /> + ) diff --git a/src/static/SVG/lottie-map.ts b/src/static/SVG/lottie-map.ts index 1b799ec..9055a4e 100644 --- a/src/static/SVG/lottie-map.ts +++ b/src/static/SVG/lottie-map.ts @@ -13,4 +13,5 @@ export const JSON_MAP = { loading6: _uri('loading6.json'), loading7: _uri('loading7.json'), success: _uri('success.json'), + initial_success: _uri('initial_success.json'), } as const diff --git a/src/static/tabbarIcon/home.png b/src/static/tabbarIcon/home.png index a284a30d08ff5c0fa5f3850dd632ebd2a21b8c2b..50afec50fc22e25696913618c59943052e028de1 100644 GIT binary patch literal 1004 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 literal 3980 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 diff --git a/src/static/tabbarIcon/manage.png b/src/static/tabbarIcon/manage.png index 58b03fdec69eee502ca28cb143ca69197f3b533d..bd48f26547950784d65c7349e5ec4b198e557b4f 100644 GIT binary patch literal 1157 zcmV;01bX|4P)Px#1am@3R0s$N2z&@+hyVZtFG)l}RCt{2oqbN@Fcidx)gFYK)IC{-n{X57X627< zL|NK+Y(IY`{z+Dmh~FE}q;7}^ykVl^?&ETQ1%Qu-@3X3!6X5`O0Jp$k8+pfu2pd0x zCajdQdO+wa2>5DRZEbb z&U%Y?0SoGJ33^`Q3JSFvj9e4d+RnL~_x`plOX(BhC9Tc14uEQ1=iKcP?|sRW;we6& z;i1h>48cWcOBdT{c*L3isn&jFenJQ_`hF2>ghRt0NCJGq$o$9eU{MdgTrSZKuGeemkTtp}w6msnh=dRJWm)7i-#J%o zm+&QuR)k0}9}yvl=ASYEBE$S`?1fO;d80T4#!8-+mY1@;^OVQhY82rRM4UIXBcrY!R}VlGip@CVW!1E8QQ%lz7xntSvX z00m7o&HpUD;GP1Ypr@w!YmG(s5)huL->=^+3LIu2<*1Tm$dpy9CQLl9IF3jGgl zJ_J#vpwRp9=0gxx0t$UkVLo06Dj5KUo~JP%s2c!f_0fjmv znh&907Y&YTzOuIF4P2n(_Ta|=9&TibjHT6QVD1uYgu&baM7lA16>a|b{3 zH@e+|xHoU_+TVL0YkVv7A?Rw>V0YgC`+uV8t$buEX6~G%RJ(pFBzpVxA zu;Tk)gskmkv?patNZnrii+Vj%{4>A@8n`EOCu#}W$Sjy{;_p$SBLBZfTdt*=#if4$saopJqEtPfv*VBSQWOeT}bWHOmdCK-GI X!zg6sbj~ac00000NkvXXu0mjfk6{s; literal 12720 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

;7NZC>ixMgt{n(W4!hS8?BU} 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 Hu0mjf9K?9s literal 12754 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 diff --git a/src/static/tabbarIcon/my.png b/src/static/tabbarIcon/my.png index 9f0dc9100794a6f5a08fab9459b763658e508ad5..9ab4ecbcc650cc9f863be9452fe612191caa6803 100644 GIT binary patch literal 847 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 diff --git a/src/static/tabbarIcon/my_active.png b/src/static/tabbarIcon/my_active.png index b99be93d837ddd68ad08a553606750124f85f6ad..d53d61be624e75484b19da59e67a908dd38c65fc 100644 GIT binary patch literal 1008 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 diff --git a/src/types/business/student.ts b/src/types/business/student.ts index dd450aa..42dd71a 100644 --- a/src/types/business/student.ts +++ b/src/types/business/student.ts @@ -1,8 +1,10 @@ -import { IStudentStruct } from '../entity' +import { ICourse, IStudentCollegeInfo, IStudentStruct } from '../entity' /** 获取学生信息接口返回类型 */ type TBizStudentGetInfo = { studentVo: IStudentStruct + courseVos?: ICourse[] + organizationVo?: IStudentCollegeInfo } export { TBizStudentGetInfo } diff --git a/src/types/entity/task.ts b/src/types/entity/task.ts index e66893d..3233efb 100644 --- a/src/types/entity/task.ts +++ b/src/types/entity/task.ts @@ -1,15 +1,17 @@ /** 任务的类型 */ export type TTaskItem = { title: string - time: number - desc: string + deadline: number + description: string /* 当前任务状态 */ status: 0 | 1 | 2 /* 当前任务ID */ id: number + /** 是否置顶 0:不置顶,1:置顶 */ + pin: 0 | 1 /* 标签 */ tags?: string[] - imgs?: string[] + pictureLinks?: string /* 发布人 */ publisher: string } diff --git a/src/types/entity/work.ts b/src/types/entity/work.ts index 4079e32..67b451d 100644 --- a/src/types/entity/work.ts +++ b/src/types/entity/work.ts @@ -27,6 +27,8 @@ interface IWork extends IBaseWork { publishPlatform: string /** 发布者ID */ publisherId: number + /** 是否置顶 0:不置顶,1:置顶 */ + pin: 0 | 1 } /** 通知 */ diff --git a/src/types/index copy.ts b/src/types/index copy.ts deleted file mode 100644 index 214d7fe..0000000 --- a/src/types/index copy.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './helpers' -export * from './entity' -export * from './business' diff --git a/src/utils/perfTrack/business.ts b/src/utils/perfTrack/business.ts index 174f261..dc2a64f 100644 --- a/src/utils/perfTrack/business.ts +++ b/src/utils/perfTrack/business.ts @@ -4,6 +4,7 @@ import { TTrackEventParams, blockConsole, trackEvent } from './trackEvent' const enum BUSINESS_EVENT_MAP { GOTO = 'track_goto_time', API_ERROR = 'track_api_error', + JS_ERROR = 'track_global_js_error', } /** 追踪跳转耗时 */ @@ -21,7 +22,7 @@ type TTrackAPIErrorParams = Pick & { token: string api: string reqData?: TGeneralObject | string | undefined - errMsg: any + err_msg: any } /** 网络请求错误埋点 */ export const trackAPIError = ({ @@ -29,9 +30,9 @@ export const trackAPIError = ({ api, reqData, extraParams, - errMsg, + err_msg, }: TTrackAPIErrorParams) => { - /* __PURE__ */ console.log(' === API错误埋点上报 === ', token, api, reqData, extraParams, errMsg) + /* __PURE__ */ console.log(' === API错误埋点上报 === ', token, api, reqData, extraParams, err_msg) trackEvent({ eventId: BUSINESS_EVENT_MAP.API_ERROR, extraParams: { @@ -39,7 +40,7 @@ export const trackAPIError = ({ token, api, req_data: JSON.stringify(reqData), - err_msg: JSON.stringify(errMsg), + err_msg: JSON.stringify(err_msg), }, }) } @@ -49,7 +50,7 @@ type TTrackJsErrorParams = Pick & { token: string errMsg: any location: string - errName: string + err_name: string } /** 运行时错误上报 */ export const trackJsError = ({ @@ -57,24 +58,24 @@ export const trackJsError = ({ extraParams = {}, errMsg, location, - errName, + err_name, }: TTrackJsErrorParams) => { /* __PURE__ */ console.log( ' === 运行时错误埋点上报 === ', token, location, - errName, + err_name, extraParams, errMsg, ) trackEvent({ - eventId: BUSINESS_EVENT_MAP.API_ERROR, + eventId: BUSINESS_EVENT_MAP.JS_ERROR, extraParams: { ...extraParams, token, err_msg: JSON.stringify(errMsg), location, - errName, + err_name, }, }) } diff --git a/src/utils/request/business.ts b/src/utils/request/business.ts index 3cf7fc1..8fcef39 100644 --- a/src/utils/request/business.ts +++ b/src/utils/request/business.ts @@ -1,4 +1,3 @@ -import { IUserInfo } from 'src/common-model' import { TGeneralObject } from 'src/types' import { getStorage } from '../storage' import { ResultWrap } from './Result' @@ -43,9 +42,14 @@ export const request = ( } const { data, code, msg } = originData + console.log( + ' === extraParam === ', + Object.keys(originData).filter((k) => !['code', 'data', 'msg'].includes(k)), + ) + const extraData = Object.keys(originData) .filter((k) => !['code', 'data', 'msg'].includes(k)) - .reduce((pre, cur) => (pre[cur] = originData[cur]), {}) + .reduce((obj, key) => ({ ...obj, [key]: originData[key] }), {}) resInstance = new ResultWrap({ data, @@ -58,7 +62,7 @@ export const request = ( if (!params.silent) { const { loadingNeedMask: mask } = params showToast({ - title: !type ? '执行成功~' : '执行失败了.....', + title: !type ? 'success~' : 'failed!', mask, }) } @@ -68,7 +72,7 @@ export const request = ( token: getStorage('userInfo').token || 'no_login', api: params.url, reqData: params.data, - errMsg: msg, + err_msg: msg, }) } } catch (_err) { @@ -81,7 +85,7 @@ export const request = ( if (!params.silent) { const { loadingNeedMask: mask } = params showToast({ - title: '执行失败了.....', + title: '执行失败了!', mask, }) } @@ -90,7 +94,7 @@ export const request = ( token: getStorage('userInfo').token || 'no_login', api: params.url, reqData: params.data, - errMsg: _err, + err_msg: _err, }) } resolve(resInstance) diff --git a/src/utils/request/constants.ts b/src/utils/request/constants.ts index a8873c1..7956b29 100644 --- a/src/utils/request/constants.ts +++ b/src/utils/request/constants.ts @@ -9,9 +9,9 @@ export const BUSINESS_API_ROOT_PATH = { /** 学生模块 */ WX_STU: '/wx/studentManager/student', /** 组织 */ - WX_ORG: '/wx/origination/complexAll', + WX_ORG: '/wx/organization/complexAll', /** 订阅消息 */ - WX_SUB: '/wx/notificationWork', + WX_WORK: '/wx/notificationWork/notifyAndWork', } /** @@ -42,4 +42,4 @@ export const enum STATUS_CODE { * [无用可删] * 哪些api不需要check token */ -export const NO_CHECK_TOKEN_WHITE_LIST = ['/login'] +export const NO_CHECK_TOKEN_WHITE_LIST = ['/getToken'] diff --git a/src/utils/route/goTo.ts b/src/utils/route/goTo.ts index 56bff79..b3ce8e0 100644 --- a/src/utils/route/goTo.ts +++ b/src/utils/route/goTo.ts @@ -57,7 +57,7 @@ export const goTo = ({ /** 校验是否登陆 */ if (options.authorize) { - const token = store.getState()?.common?.userInfo?.token + const token = store.getState()?.userinfoModel?.token if (!token || !isStr(token)) { /** 理论来说不需要校验checkSession,因为HOC会处理没token,如果没登陆态都走不到这里 */ showToast({ diff --git a/src/utils/storage.ts b/src/utils/storage.ts index 99b951e..4373d32 100644 --- a/src/utils/storage.ts +++ b/src/utils/storage.ts @@ -1,10 +1,11 @@ import Taro from '@tarojs/taro' -import { IUserInfo } from 'src/common-model' +import { IUserInfo, IRuntimeCache } from 'src/model' import { isObj } from './jsBase' /** 可存储的storage接口 */ export interface IStorageData { - userInfo: IUserInfo + userInfo: Partial + runtimeCache: Partial } type TStorageKey = keyof IStorageData diff --git a/src/utils/subscribe.ts b/src/utils/subscribe.ts index effe37c..df8a2c5 100644 --- a/src/utils/subscribe.ts +++ b/src/utils/subscribe.ts @@ -1,11 +1,25 @@ import Taro from '@tarojs/taro' import { store } from 'src/store' -import { ISystemInfo } from 'src/common-model' +import { ISystemInfo } from 'src/model' import { showModal, showToast } from './extraUiEffect' import { URL, goTo } from './route' type TSubscribeOptions = { - tplId: string[] + tplId: typeof tplIds +} + +/** 需要被订阅的模版 */ +export const tplIds = [ + /** 作业通知 */ + 'X4et8qrCY9UA3yXAB1FfZ16UXOU4-2wglppSqYxTAII', + /** 作业提交提醒 */ + 'V8JzyKTZZ16srBpi1QQMMUDCLMYzutIVvWGy8irgxiM', +] + +/** 订阅模版汉字枚举 */ +export const tplNameEnum = { + ['X4et8qrCY9UA3yXAB1FfZ16UXOU4-2wglppSqYxTAII']: '作业通知', + ['V8JzyKTZZ16srBpi1QQMMUDCLMYzutIVvWGy8irgxiM']: '作业提交提醒', } const handleFailAuth = async (osStorage: ISystemInfo) => { @@ -27,13 +41,13 @@ const handleFailAuth = async (osStorage: ISystemInfo) => { } /** 更新系统状态,组织模态框多次弹出 */ - store.dispatch.common.update_SystemInfo({ ...osStorage, isAuthorizeSubscribePop: true }) + store.dispatch.systemModel.update_SystemInfo({ ...osStorage, isAuthorizeSubscribePop: true }) return Promise.resolve({ errno: 0 }) } /** 基础订阅能力 */ export const subscribe = ({ tplId }: TSubscribeOptions): Promise<{ errno: 0 | 1 }> => { - const osStorage = store.getState().common.system + const osStorage = store.getState().systemModel return new Promise<{ errno: 0 | 1 }>((resolve) => Taro.requestSubscribeMessage({ tmplIds: [...tplId], @@ -72,16 +86,21 @@ export const subscribe = ({ tplId }: TSubscribeOptions): Promise<{ errno: 0 | 1 * * ! 注意:只能用于类式组件,函数式组件不可用 */ -export function subscribeHOF(tplIds: string[]) { +export function subscribeHOF(tplId: typeof tplIds) { return function (_target, _key, descriptor) { /** 获取原函数 */ const originalFunction = descriptor.value /** 额外执行订阅逻辑 */ descriptor.value = async function () { /** 先等授权逻辑走完 */ - subscribe({ tplId: tplIds }) + subscribe({ tplId }) return originalFunction.apply(this, arguments) } return descriptor } } + +/** 需要和后端通信的订阅请求 */ +// export function messageWithBackendSubscribe(tplId: keyof typeof tplIds) { +// const +// }