From e33657c6610ca68d7528a7fe6bc89784dc0abcd9 Mon Sep 17 00:00:00 2001 From: king <2229249788@qq.com> Date: Thu, 3 Aug 2023 18:05:10 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A7=81=E9=9D=A2=E4=BC=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/meeting.ts | 32 +- src/api/request.ts | 9 +- src/components/button/MyButton.tsx | 33 +- src/components/button/myButton.module.scss | 11 +- src/components/popPut/popPut.tsx | 2 +- src/pages/manage/meetings/meetings.config.ts | 4 + .../manage/meetings/meetings.module.scss | 43 +++ src/pages/manage/meetings/meetings.tsx | 74 +++++ .../spotMeeting/spotMeeting.module.scss | 66 +++- src/pages/manage/spotMeeting/spotMeeting.tsx | 289 +++++++++++++----- src/static/css/module.scss | 4 + src/static/img/code.png | Bin 0 -> 10683 bytes 12 files changed, 460 insertions(+), 107 deletions(-) create mode 100644 src/pages/manage/meetings/meetings.config.ts create mode 100644 src/pages/manage/meetings/meetings.module.scss create mode 100644 src/pages/manage/meetings/meetings.tsx create mode 100644 src/static/img/code.png 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 0000000000000000000000000000000000000000..f62705836a77d9f9bb46958ce4f87cd9ce73b36f GIT binary patch literal 10683 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 literal 0 HcmV?d00001