diff --git a/src/api/meeting.ts b/src/api/meeting.ts index 0f519bf..6612c92 100644 --- a/src/api/meeting.ts +++ b/src/api/meeting.ts @@ -1,7 +1,33 @@ import {request} from "@/api/request"; -export const meetingAPi={ - qrcodeKey() { - return request('/api/v1/auth/login/qrcode/key', "GET") +export interface Meeting { + id: number + /** 部门ID */ + department_id: number; + /** 现场会描述 */ + description: string; + /** 预计结束时间 */ + estimate_end_time: number; + /** 预计开始时间 */ + estimate_start_time: number; + /** 现场会标题 */ + name: string; +} + +export const meetingAPi = { + setMeetings(data: Meeting) { + return request<{ id: number }>('/api/v1/meetings/meeting', "POST", data) + }, + setMeeting(id: string) { + return request(`/api/v1/meetings/meeting/${id}`, "GET") + }, + setList(page: number, page_size: number) { + return request<{data:Meeting[],total:number}>(`/api/v1/meetings/meeting?page=${page}&page_size=${page_size}`, "GET") + }, + exists() { + return request('/api/v1/meetings/exists', "GET") + }, + del(id:number){ + return request(`/api/v1/meetings/meeting/${id}`,"DELETE") } } diff --git a/src/api/request.ts b/src/api/request.ts index fcdf070..1851952 100644 --- a/src/api/request.ts +++ b/src/api/request.ts @@ -77,9 +77,9 @@ export function request( ...option, success(res) { try { - const data = res.data as any - if (data?.code === 0 && res.statusCode === 200) { - resolve(data.data || []) + const data = res?.data as any + if (data?.code === 0 && res?.statusCode === 200) { + resolve(data?.data || []) } else if (res.statusCode === 401) { Taro.showModal({ title: "登录过期,需重新登陆", @@ -91,7 +91,7 @@ export function request( } else { reject(null) Taro.showToast({ - title: data.msg || data.message || ERROR_STATUS[res.statusCode] || '请求错误~', + title: data?.msg || data?.message || ERROR_STATUS[res.statusCode] || '请求错误~', icon: 'error' }) } @@ -101,7 +101,6 @@ export function request( }, fail(err) { const errMsg = err?.errMsg - console.log(err) Taro.showToast({title: ERROR_STATUS[errMsg] || ERROR_STATUS['DEFAULT'], icon: 'error'}) reject(null) } diff --git a/src/components/button/MyButton.tsx b/src/components/button/MyButton.tsx index 76c0d90..7b4e37a 100644 --- a/src/components/button/MyButton.tsx +++ b/src/components/button/MyButton.tsx @@ -2,6 +2,7 @@ import {CSSProperties, FC} from "react"; import {Button, View} from "@tarojs/components"; import styles from './myButton.module.scss' import {ButtonProps} from "@tarojs/components/types/Button"; +import Loading from "@/components/loading"; interface Props extends ButtonProps { fillet?: boolean @@ -11,8 +12,8 @@ interface Props extends ButtonProps { const MyButton: FC = (props) => { - const buttonStyle = (): CSSProperties => { - const style: CSSProperties = {} + const buttonStyle = (): CSSProperties | string => { + let style: CSSProperties | string = {} switch (props.type) { case 'default': style.background = '#f5f8f7' @@ -29,18 +30,30 @@ const MyButton: FC = (props) => { style.width = props.width + "px" } + if (props.style && typeof props.style === 'object') { + style = { + ...style, + ...props.style + } + } + return style } return ( - - - + ) } export default MyButton diff --git a/src/components/button/myButton.module.scss b/src/components/button/myButton.module.scss index 51407b1..381123c 100644 --- a/src/components/button/myButton.module.scss +++ b/src/components/button/myButton.module.scss @@ -5,15 +5,10 @@ font-size: 32rpx; border: none !important; outline: none !important; - position: absolute; margin: 0; padding: 0; box-sizing: border-box; -} - -.MybuttonBox { - position: relative; - height: 76rpx; - line-height: 76rpx; - flex: 1; + display: flex; + justify-content:center; + align-items: center; } diff --git a/src/components/popPut/popPut.tsx b/src/components/popPut/popPut.tsx index ebc6489..d9f2a0d 100644 --- a/src/components/popPut/popPut.tsx +++ b/src/components/popPut/popPut.tsx @@ -7,7 +7,7 @@ import CustomPageContainer from "@/components/custom-page-container/custom-page- interface Props { height?: number | string title: string - content?: string + content?: string | ReactNode chevron?: boolean image?: string isProp?: boolean diff --git a/src/pages/manage/meetings/meetings.config.ts b/src/pages/manage/meetings/meetings.config.ts new file mode 100644 index 0000000..8617280 --- /dev/null +++ b/src/pages/manage/meetings/meetings.config.ts @@ -0,0 +1,4 @@ +export default definePageConfig({ + navigationBarTitleText: '见面会记录', + onReachBottomDistance: 30 +}) diff --git a/src/pages/manage/meetings/meetings.module.scss b/src/pages/manage/meetings/meetings.module.scss new file mode 100644 index 0000000..075fb8b --- /dev/null +++ b/src/pages/manage/meetings/meetings.module.scss @@ -0,0 +1,43 @@ +.meeting { + display: flex; + justify-content: space-between; + margin-bottom: 20rpx; +} + +.title { + position: relative; + flex: 1; + width: 70%; + background: #fff; + padding: 20rpx; + border-radius: 10rpx; + overflow: hidden; + box-sizing: border-box; +} + + +.overdue { + position: absolute; + top: 0; + bottom: 0; + right: 0; + left: 0; + text-align: center; + color: #fff; + display: flex; + justify-content: center; + align-items: center; + background: rgba(#000, .8); +} + + +.del { + border-radius: 10rpx; + background: #FF3A2F; + display: flex; + align-items: center; + color: #fff; + width: 100rpx; + justify-content: center; + margin-left: 20rpx; +} diff --git a/src/pages/manage/meetings/meetings.tsx b/src/pages/manage/meetings/meetings.tsx new file mode 100644 index 0000000..ab574cf --- /dev/null +++ b/src/pages/manage/meetings/meetings.tsx @@ -0,0 +1,74 @@ +import {FC, useCallback, useEffect, useState} from "react"; +import {View} from "@tarojs/components"; +import {Meeting, meetingAPi} from "@/api"; +import styles from './meetings.module.scss' +import Taro, {useReachBottom} from "@tarojs/taro"; +import Empty from "@/components/empty/empty"; +import {formatDate} from "@/utils/time"; + +const MeetingsConfig: FC = () => { + const [page, setPage] = useState(1) + const [meeting, setMeeting] = useState([]) + const [total, setTotal] = useState(0) + + const getData = useCallback(async () => { + try { + const res = await meetingAPi.setList(1, 10) + setTotal(res.total) + setMeeting([ + ...(meeting || []), + ...res.data + ]) + } catch (e) { + } + }, [page]) + + function del(id: number, index: number) { + try { + Taro.showModal({ + title: '确定删除', + async success({confirm}) { + if (confirm) { + await meetingAPi.del(id) + + const oldMeeting: Meeting[] = JSON.parse(JSON.stringify(meeting)) + oldMeeting.splice(index, 1) + setMeeting(oldMeeting) + } + } + }) + } catch (e) { + } + } + + useReachBottom(useCallback(() => { + if (meeting?.length < total) { + setPage(page + 1) + } + }, [total, meeting])) + + useEffect(() => { + getData() + }, [page]) + + return ( + + + { + meeting.length ? + meeting.map((d, index) => + + {d.name} + {formatDate(new Date(d.estimate_start_time), "MM-dd")} 至 {formatDate(new Date(d.estimate_start_time), "MM-dd")} + + {Date.now() > d.estimate_end_time && 已过期} + + del(d.id, index)}>删除 + ) + : + } + + ) +} + +export default MeetingsConfig diff --git a/src/pages/manage/spotMeeting/spotMeeting.module.scss b/src/pages/manage/spotMeeting/spotMeeting.module.scss index 56d99b6..d4d3355 100644 --- a/src/pages/manage/spotMeeting/spotMeeting.module.scss +++ b/src/pages/manage/spotMeeting/spotMeeting.module.scss @@ -1,5 +1,67 @@ .page { - background: #fff; + background: #00D6AC; min-height: 100vh; - padding: 20px; + padding: 40px; + position: absolute; + top: 0; + left: 0; + width: 100%; + box-sizing: border-box; +} + + +.box { + width: 100%; + padding: 60rpx 20rpx 20rpx 20rpx; + background: #fff; + box-sizing: border-box; + border-radius: 15rpx; + text-align: center; +} + + +.code { + width: 300rpx; + margin: 50rpx auto 70rpx; +} + +.choice { + border-top: 1px dashed #ddd; + padding: 40rpx 0 0; + position: relative; + + &:after { + content: ''; + display: block; + background: #00D6AC; + width: 40rpx; + height: 40rpx; + border-radius: 100%; + position: absolute; + left: -40rpx; + top: -20rpx; + } + + + &:before { + content: ''; + display: block; + background: #00D6AC; + width: 40rpx; + height: 40rpx; + border-radius: 100%; + position: absolute; + right: -40rpx; + top: -20rpx; + } +} + +.button { + margin: 30rpx auto; + box-shadow: 0 0 10rpx rgba(#00d6ac, .5); +} + +.buttonDel { + margin: 30rpx auto; + box-shadow: 0 0 10rpx rgba(#c94f4f, .5); } diff --git a/src/pages/manage/spotMeeting/spotMeeting.tsx b/src/pages/manage/spotMeeting/spotMeeting.tsx index 10f077c..79428e7 100644 --- a/src/pages/manage/spotMeeting/spotMeeting.tsx +++ b/src/pages/manage/spotMeeting/spotMeeting.tsx @@ -1,82 +1,92 @@ import {FC, useCallback, useEffect, useState} from "react"; -import {Image, Picker, View} from "@tarojs/components"; -import styles from './spotMeeting.module.scss' -import Taro from "@tarojs/taro"; -import {curriculum, meetingAPi} from "@/api"; +import {Form, Image, Input, Picker, Textarea, View} from "@tarojs/components"; +import Taro, {getSetting, authorize} from "@tarojs/taro"; +import {curriculum, Meeting, meetingAPi} from "@/api"; import {formatDate} from "@/utils/time"; -import {getSetting, authorize} from "@tarojs/taro"; import PopPut from "@/components/popPut/popPut"; import MyButton from "@/components/button/MyButton"; +import styles from './spotMeeting.module.scss' +import code from '@/static/img/code.png' +import Icon from "@/components/icon"; const SpotMeeting: FC = () => { + const path = encodeURIComponent("/pages/meeting/meeting") + const params = Taro.getCurrentInstance().router?.params as { id: string | undefined } const [manages, setManages] = useState([]) const [start, setStart] = useState(formatDate(new Date(), "YY-MM-dd hh:00:00")) const [end, setEnd] = useState(formatDate(new Date(), "YY-MM-dd 18:00:00")) - const [tempFilePath, setTempFilePath] = useState(null); - const [error, setError] = useState(null) const [depid, setDepid] = useState(null) - const [isDownloading, setDownloading] = useState(false) - - - const change = useCallback((e) => { - setDepid(() => manages[Number(e.detail.value)]?.id) - }, [manages]) + const [imgUrl, setImgUrl] = useState('') + const [name, setName] = useState('') + const [description, setDescription] = useState('') + const [loading, setLoading] = useState(false) useEffect(() => { curriculum.department().then(res => { setManages(res.data) }) - meetingAPi.qrcodeKey().then((res: any) => { - if (res.dep_id && res.end_time && res.start_time) { - setDepid(res.dep_id) - setEnd(formatDate(new Date(res.end_time), "YY-MM-dd 18:00:00")) - setStart(formatDate(new Date(res.start_time), "YY-MM-dd 08:00:00")) - } - }) - }, []) - - useEffect(() => { - if (!depid || isDownloading) { - return + setLoading(true) + if (params.id != undefined) { + meetingAPi.setMeeting(params.id).then(res => { + if (!Array.isArray(res)) { + setDepid(res.department_id) + setName(res.name) + setDescription(res.description) + setEnd(formatDate(new Date(res.estimate_end_time), "YY-MM-dd 18:00:00")) + setStart(formatDate(new Date(res.estimate_start_time), "YY-MM-dd 08:00:00")) + downUrl(res.id, false) + } else { + setLoading(false) + } + }) + } else { + meetingAPi.exists().then(res => { + if (!Array.isArray(res)) { + setDepid(res.department_id) + setName(res.name) + setDescription(res.description) + setEnd(formatDate(new Date(res.estimate_end_time), "YY-MM-dd 18:00:00")) + setStart(formatDate(new Date(res.estimate_start_time), "YY-MM-dd 08:00:00")) + downUrl(res.id, false) + } else { + setLoading(false) + } + }) } + }, []) - Taro.showLoading() - setDownloading(true) - const startTime = new Date(start).getTime() - const endTime = new Date(end).getTime() - const path = encodeURIComponent("/pages/meeting/meeting") - - const qrcodeUrl = `${process.env.TARO_APP_API}/official/qrcode?depid=${depid}&start_time=${startTime}&end_time=${endTime}&path=${path}&t=${Date.now()}` + const change = useCallback((e) => { + setDepid(() => manages[Number(e.detail.value)]?.id) + }, [manages]) - if (process.env.TARO_ENV === 'h5') { - setTempFilePath(qrcodeUrl) - setDownloading(false) + const change_start = useCallback((time: string) => { + const mil = new Date(time).getTime() + const endMil = new Date(end).getTime() + if (mil > endMil) { + Taro.showToast({title: '大于结束时间', icon: 'error'}) } else { - Taro.downloadFile({ - url: qrcodeUrl, - success(res) { - setTempFilePath(res.tempFilePath) - }, - fail() { - setError("请求失败"); - }, - complete() { - setDownloading(false) - } - }) + setStart(time) } - Taro.hideLoading() - }, [depid, end, start]) + }, [end]) + const change_end = useCallback((time: string) => { + const mil = new Date(time).getTime() + const startMil = new Date(start).getTime() + if (mil < startMil) { + Taro.showToast({title: '小于开始时间', icon: 'error'}) + } else { + setEnd(time) + } + }, [start]) const handleWriteFile = useCallback(() => { - if (tempFilePath == null) { + if (imgUrl == null) { Taro.showToast({title: '下载失败', icon: 'error'}) return } Taro.saveImageToPhotosAlbum({ - filePath: tempFilePath, + filePath: imgUrl, success() { Taro.showModal({title: '下载成功'}) }, @@ -84,12 +94,11 @@ const SpotMeeting: FC = () => { Taro.showToast({title: '下载失败', icon: 'error'}) } }) - - }, [tempFilePath]) + }, [imgUrl]) const handleSaveCode = useCallback(() => { if (process.env.TARO_ENV === 'h5') { - Taro.showToast({title: '请截屏', icon: 'error'}) + Taro.showToast({title: '长按保存二维码', icon: 'error'}) } else { getSetting({ success: function ({authSetting}) { @@ -108,41 +117,165 @@ const SpotMeeting: FC = () => { }, }); } - }, [tempFilePath]); + }, [imgUrl]); + const downUrl = (id: number, down = true) => { + Taro.showLoading({title: '加载二维码'}) + const url = process.env.TARO_APP_API + '/official/qrcode?' + 'meeting_id=' + id + '&path=' + path + + if (process.env.TARO_ENV !== 'h5') { + Taro.downloadFile({ + url, + success(res) { + setImgUrl(res.tempFilePath) + if (down) { + handleSaveCode() + } + }, + fail() { + Taro.showModal({title: '二维码生成失败'}) + }, + complete() { + setLoading(false) + Taro.hideLoading() + } + }) + } else { + setTimeout(() => {setImgUrl(url)}) + if (down) {handleSaveCode()} + Taro.hideLoading() + setLoading(false) + } + } + + + async function submit(e) { + if (imgUrl) { // 已有 + handleSaveCode() + return + } + + const values: Meeting = e.detail.value + for (const [key, value] of Object.entries(values)) { + if (!value && key !== 'description') { + Taro.showToast({title: '请认真填写', icon: 'error'}) + return + } + } + if (!depid) { + Taro.showToast({title: '请选择部门', icon: 'error'}) + return + } + + setLoading(true) + try { + const res = await meetingAPi.setMeetings({ + ...values, + estimate_end_time: new Date(end).getTime(), + estimate_start_time: new Date(start).getTime(), + department_id: depid + }) + downUrl(res.id) + } catch (e) { + + } + setLoading(false) + } + + function jumpMeeings() { + Taro.navigateTo({url: '/pages/manage/meetings/meetings'}) + } + + function imageOnLoad() { + Taro.hideLoading() + } + + useEffect(() => { + if (imgUrl) { + setImgUrl('') + } + }, [start, end, name, depid, description]) return ( - setStart(e.detail.value + ' 8:00:00')} name='start'> - - + + 填完信息才能生成二维码 + + { + imgUrl + ? + : + } + - setEnd(e.detail.value + ' 18:00:00')} name='end'> - - + +
+ setName(e.detail.value)} + />} + chevron + /> + change_start(e.detail.value + ' 8:00:00')} + name='estimate_start_time'> + + + change_end(e.detail.value + ' 18:00:00')} + name='estimate_end_time'> + + + + x.id == depid)?.name}/> + - - - x.id == depid)?.name}/> - - + - {tempFilePath && - setError(null)} - onError={(e) => setError(e.detail.errMsg)} - style={{width: '80%'}} - /> - {error && {error}} - {process.env.TARO_ENV !== 'h5' && 下载} - {process.env.TARO_ENV === 'h5' && 请截图保存} + + 保存二维码 + + + + + 历史列表 +
-
}
) } diff --git a/src/static/css/module.scss b/src/static/css/module.scss index efef0fb..b3ff8e8 100644 --- a/src/static/css/module.scss +++ b/src/static/css/module.scss @@ -11,6 +11,10 @@ page, +taro-button-core::after { + border: none !important; +} + body { font-size: 32rpx; } diff --git a/src/static/img/code.png b/src/static/img/code.png new file mode 100644 index 0000000..f627058 Binary files /dev/null and b/src/static/img/code.png differ