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 a284a30..50afec5 100644 Binary files a/src/static/tabbarIcon/home.png and b/src/static/tabbarIcon/home.png differ diff --git a/src/static/tabbarIcon/home_active.png b/src/static/tabbarIcon/home_active.png index 31904d5..e32c562 100644 Binary files a/src/static/tabbarIcon/home_active.png and b/src/static/tabbarIcon/home_active.png differ diff --git a/src/static/tabbarIcon/manage.png b/src/static/tabbarIcon/manage.png index 58b03fd..bd48f26 100644 Binary files a/src/static/tabbarIcon/manage.png and b/src/static/tabbarIcon/manage.png differ diff --git a/src/static/tabbarIcon/manage_active.png b/src/static/tabbarIcon/manage_active.png index 3766e37..deeb006 100644 Binary files a/src/static/tabbarIcon/manage_active.png and b/src/static/tabbarIcon/manage_active.png differ diff --git a/src/static/tabbarIcon/my.png b/src/static/tabbarIcon/my.png index 9f0dc91..9ab4ecb 100644 Binary files a/src/static/tabbarIcon/my.png and b/src/static/tabbarIcon/my.png differ diff --git a/src/static/tabbarIcon/my_active.png b/src/static/tabbarIcon/my_active.png index b99be93..d53d61b 100644 Binary files a/src/static/tabbarIcon/my_active.png and b/src/static/tabbarIcon/my_active.png differ 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 +// }