yhy
Dawn_Ocean 2024-03-06 21:49:35 +08:00
commit 54091bb6b3
14 changed files with 434 additions and 11 deletions

View File

@ -9,4 +9,8 @@ node_modules/
.husky .husky
.prettierignore .prettierignore
.env.* .env.*
project.*.json <<<<<<< HEAD
project.*.json
=======
**/*.svg
>>>>>>> dev

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1709729147345" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7587" width="32" height="32" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M960 170.56L869.44 80 512 437.44 154.56 80 64 170.56 421.44 528 64 885.44l90.56 90.56L512 618.56 869.44 976 960 885.44 602.56 528 960 170.56z" p-id="7588" fill="#d4237a"></path></svg>

After

Width:  |  Height:  |  Size: 514 B

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1709729289782" class="icon" viewBox="0 0 1418 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8708" width="44.3125" height="32" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M491.191709 1023.803077L0.136305 539.63733l111.888035-110.273886 379.167369 373.89186L1305.549204 0.433064 1417.437238 110.706951 491.191709 1023.803077z" p-id="8709" fill="#12c53d"></path></svg>

After

Width:  |  Height:  |  Size: 531 B

View File

@ -0,0 +1,3 @@
export default {
component: true,
};

View File

@ -0,0 +1,17 @@
import { View } from '@tarojs/components';
import { AtDivider } from 'taro-ui';
import pt from '@/plain-text';
export default () => {
const blankHeight = 120;
return (
<View>
<AtDivider
content={pt.get().pageFooter.dividerText}
fontColor='#dddddd'
lineColor='#dddddd'
/>
<View style={{ height: blankHeight }}></View>
</View>
);
};

View File

@ -0,0 +1,107 @@
import { Component, ReactNode } from 'react';
import { View, Image } from '@tarojs/components';
import { AtTimeline } from 'taro-ui';
import pt from '@/plain-text';
import tick from '@/assets/icons/MainPage/tick.svg';
import cross from '@/assets/icons/MainPage/cross.svg';
export class DutyData {
constructor() {
this.isInDuty = false;
this.inDutyCnt = 3;
this.currentDuty = '2';
this.offDutyReason = '学园维修';
this.dutyRecoverTime = '下周一';
}
isInDuty: boolean;
inDutyCnt: number;
currentDuty: 'off' | '1' | '2' | '3';
offDutyReason: string; // from backend
dutyRecoverTime: string; // from backend
}
class Card extends Component {
props = {
isInDuty: false,
};
render(): ReactNode {
const inDuty = this.props.isInDuty;
const dc = pt.get().mainPage.dutyCard;
const title = inDuty ? dc.inDuty.title : dc.offDuty.title;
const iconsrc = inDuty ? tick : cross;
return (
<View>
<View
style={{
display: 'flex',
alignItems: 'center',
marginBottom: 20,
}}
>
<Image
src={iconsrc}
style={{
width: 24,
height: 24,
}}
/>
<View
style={{
marginLeft: 10,
fontSize: 36,
}}
>
{title}
</View>
</View>
</View>
);
}
}
export class DutyInfo extends Component {
props = {
data: new DutyData(),
};
offDutyContent(): ReactNode {
const data = this.props.data;
const od = pt.get().mainPage.dutyCard.offDuty;
return (
<View>
<Card isInDuty={data.isInDuty} />
<AtTimeline
items={[
{ title: od.reason(data.offDutyReason) },
{ title: od.recoverTime(data.dutyRecoverTime) },
]}
/>
</View>
);
}
inDutyContent(): ReactNode {
const data = this.props.data;
const id = pt.get().mainPage.dutyCard.inDuty;
return (
<View>
<Card isInDuty={data.isInDuty} />
<AtTimeline
items={[
{ title: id.currentDutyText(data.currentDuty) },
{ title: id.inDutyCnt(data.inDutyCnt) },
]}
/>
</View>
);
}
render(): ReactNode {
if (this.props.data.isInDuty) {
return this.inDutyContent();
} else {
return this.offDutyContent();
}
}
}

View File

@ -0,0 +1,24 @@
import { Component, ReactNode } from 'react';
import { View } from '@tarojs/components';
import { AtTimeline } from 'taro-ui';
import pt from '@/plain-text';
export class StepInfo extends Component {
render(): ReactNode {
return (
<View>
<AtTimeline items={pt.get().mainPage.stepList}></AtTimeline>
</View>
);
}
}
export class TipsInfo extends Component {
render(): ReactNode {
return (
<View>
<AtTimeline items={pt.get().mainPage.tipsList}></AtTimeline>
</View>
);
}
}

View File

@ -0,0 +1,15 @@
import React from 'react';
import { View } from '@tarojs/components';
import pt from '@/plain-text';
export default class TitleCard extends React.Component {
render(): React.ReactNode {
const mainPage = pt.get().mainPage;
return (
<View className='page-title'>
<View className='at-article__h1'>{mainPage.mainTitleLine}</View>
<View className='at-article__h2'>{mainPage.subTitleLine}</View>
</View>
);
}
}

View File

@ -1,12 +1,81 @@
import { View, Text } from '@tarojs/components'; import { View } from '@tarojs/components';
import { Component, ReactNode } from 'react'; import { Component, ReactNode } from 'react';
import Taro from '@tarojs/taro'; import Taro from '@tarojs/taro';
import type CustomTabBar from '../../custom-tab-bar'; import { AtCard, AtAccordion } from 'taro-ui';
import type CustomTabBar from '@/custom-tab-bar';
import PageFooter from '@/components/PageFooter/PageFooter';
import pt from '@/plain-text';
import './index.scss'; import './index.scss';
import TitleCard from './TitleCard';
import { DutyInfo, DutyData } from './DutyInfo';
import { StepInfo, TipsInfo } from './StepTipsInfo';
class Index extends Component { class CardContent {
title: string;
note: string;
extra: JSX.Element | string;
content: () => JSX.Element;
}
function mainPageCard(c: CardContent): JSX.Element {
return (
<View style={{ marginTop: 10 }}>
<AtCard note={c.note} extra={c.extra} title={c.title}>
{c.content()}
</AtCard>
</View>
);
}
class ExpandItem extends Component {
state = { state = {
msg: 'Hello World!', open: false,
};
props = {
title: '',
content: <View></View>,
};
handleClick(value: boolean) {
this.setState({ open: value });
}
render(): ReactNode {
return (
<View>
<AtAccordion
open={this.state.open}
onClick={this.handleClick.bind(this)}
title={this.props.title}
>
{this.props.content}
</AtAccordion>
</View>
);
}
}
export default class Index extends Component {
state = {
dutyData: new DutyData(),
dutyInfoCard: {
title: pt.get().mainPage.cardTitle.dutyInfo,
note: 'Tips',
extra: '额外信息',
content: () => <DutyInfo data={this.state.dutyData} />,
},
stepInfoCard: {
title: pt.get().mainPage.cardTitle.stepInfo,
note: 'Tips 请在20:30以前取走自己的物品哦',
extra: '额外信息',
content: () => <StepInfo />,
},
tipsInfoCard: {
title: pt.get().mainPage.cardTitle.tipsInfo,
note: 'Tips',
extra: '额外信息',
content: () => <TipsInfo />,
},
}; };
// 以下是TabBar相关 // 以下是TabBar相关
@ -18,12 +87,20 @@ class Index extends Component {
// 以上是TabBar相关 // 以上是TabBar相关
render(): ReactNode { render(): ReactNode {
const mainPage = pt.get().mainPage;
return ( return (
<View> <View>
<Text>{this.state.msg}</Text> <TitleCard />
<View style={{ marginTop: 30 }}>
{mainPageCard(this.state.dutyInfoCard)}
{mainPageCard(this.state.tipsInfoCard)}
<ExpandItem
title={mainPage.expandTitle.stepInfo}
content={mainPageCard(this.state.stepInfoCard)}
/>
</View>
<PageFooter />
</View> </View>
); );
} }
} }
export default Index;

View File

@ -1,10 +1,60 @@
import { View } from '@tarojs/components';
import { Component, ReactNode } from 'react'; import { Component, ReactNode } from 'react';
import Taro from '@tarojs/taro'; import { AtForm, AtInput, AtButton } from 'taro-ui';
import './inform.scss'; import './inform.scss';
export default class InformPage extends Component { export default class InformPage extends Component {
state = {
phone: '',
name: '',
};
handleChangePhone(phone: string) {
this.setState({
phone: phone,
});
return phone;
}
handleChangeName(name: string) {
this.setState({
name: name,
});
return name;
}
onSubmit() {
console.log(this.state.name, this.state.phone);
}
onReset() {
this.setState({
phone: '',
name: '',
});
}
render(): ReactNode { render(): ReactNode {
return <View></View>; return (
<AtForm
onSubmit={this.onSubmit.bind(this)}
onReset={this.onReset.bind(this)}
>
<AtInput
name='phone'
title='手机号码'
type='text'
placeholder='便于查询工单'
value={this.state.phone}
onChange={this.handleChangePhone.bind(this)}
/>
<AtInput
required
name='name'
title='真实姓名'
type='text'
placeholder='必填,与工单绑定'
value={this.state.name}
onChange={this.handleChangeName.bind(this)}
/>
<AtButton formType='submit'></AtButton>
<AtButton formType='reset'></AtButton>
</AtForm>
);
} }
} }

View File

@ -0,0 +1,77 @@
export interface MainPageText {
mainTitleLine: string;
subTitleLine: string;
cardTitle: {
dutyInfo: string;
stepInfo: string;
tipsInfo: string;
};
expandTitle: {
stepInfo: string;
tipsInfo: string;
};
stepList: Array<{ title: string }>;
tipsList: Array<{ title: string }>;
dutyCard: {
offDuty: {
title: string;
reason: (s: string) => string;
recoverTime: (t: string) => string;
};
inDuty: {
title: string;
currentDutyText: (c: 'off' | '1' | '2' | '3') => string;
inDutyCnt: (n: number) => string;
};
};
}
export const mainPageZhCn: MainPageText = {
mainTitleLine: '您好这里是E志者协会',
subTitleLine: '维修请至【东三-204】实验室',
cardTitle: {
dutyInfo: '204值班情况',
stepInfo: '维修步骤',
tipsInfo: '注意事项',
},
expandTitle: {
stepInfo: '查看维修步骤',
tipsInfo: '查看注意事项',
},
stepList: [
{ title: '线上填写工单' },
{ title: '去`东三-204`实验室维修电脑' },
{ title: '等待电脑维修' },
{ title: '维修结束,取回电脑' },
],
tipsList: [
{ title: '戴尔、Surface、外星人、苹果电脑不能拆机哦~' },
{ title: '数据无价,请随时做好数据备份哦~' },
{ title: '204也是实验室请遵守实验室纪律请勿饮食~' },
{ title: '我们是志愿服务,不收任何礼物哦~' },
],
dutyCard: {
offDuty: {
title: '未值班',
reason: s => '值班停止原因:' + s,
recoverTime: t => '恢复值班时间:' + t,
},
inDuty: {
title: '值班中',
currentDutyText: c => {
switch (c) {
case 'off':
return '当前未值班';
case '1':
return '第一班 13:30-16:00';
case '2':
return '第二班 16:00-18:00';
case '3':
return '第三班 18:00-20:30';
}
},
inDutyCnt: n => '当前值班人数:' + n,
},
},
};

View File

@ -0,0 +1,7 @@
export interface PageFooterText {
dividerText: string;
}
export const pageFooterZhCn: PageFooterText = {
dividerText: 'EVA Notify',
};

View File

@ -0,0 +1,40 @@
import { PageFooterText, pageFooterZhCn } from './PageFooter';
import { MainPageText, mainPageZhCn } from './MainPage';
interface TextRecord {
pageFooter: PageFooterText;
mainPage: MainPageText;
}
const textZhCn: TextRecord = {
pageFooter: pageFooterZhCn,
mainPage: mainPageZhCn,
};
// type Lang = 'zh_CN' | 'en_US' | ...;
type Lang = 'zh_CN';
class PlainText {
private readonly textZhCn: TextRecord;
private lang: Lang;
constructor() {
this.textZhCn = textZhCn;
this.lang = 'zh_CN';
}
setLang(lang: Lang) {
this.lang = lang;
}
get(): TextRecord {
if (this.lang == 'zh_CN') {
return this.textZhCn;
}
return this.textZhCn;
}
}
const pt = new PlainText();
export default pt;