Commit c423ca2b by 姜雷

添加报修页面

parent 0a46b9c3
// https://github.com/michael-ciniawsky/postcss-load-config
module.exports = {
plugins: {
'postcss-flexbugs-fixes': {},
'postcss-import': {},
'postcss-url': {},
'postcss-aspect-ratio-mini': {},
'postcss-write-svg': {
utf8: false,
},
'postcss-cssnext': {},
'postcss-px-to-viewport': {
viewportWidth: 640, // (Number) The width of the viewport.
viewportHeight: 1136, // (Number) The height of the viewport.
unitPrecision: 5, // (Number) The decimal numbers to allow the REM units to grow to.
viewportUnit: 'vw', // (String) Expected units.
selectorBlackList: ['.ignore', '.hairlines'], // (Array) The selectors to ignore and leave as px.
minPixelValue: 1, // (Number) Set the minimum pixel value to replace.
mediaQuery: false, // (Boolean) Allow px to be converted in media queries.
},
'postcss-viewport-units': {},
cssnano: {
preset: 'advanced',
autoprefixer: false,
'postcss-zindex': false,
},
},
};
......@@ -57,34 +57,7 @@ module.exports = function override(config, env) {
},
{
loader: require.resolve('postcss-loader'),
options: {
// Necessary for external CSS imports to work
// https://github.com/facebookincubator/create-react-app/issues/2677
// ident: 'postcss',
plugins: () => [
require('postcss-flexbugs-fixes'),
require('postcss-aspect-ratio-mini'),
require('postcss-px-to-viewport')({
viewportWidth: 750, // (Number) The width of the viewport.
viewportHeight: 1334, // (Number) The height of the viewport.
unitPrecision: 5, // (Number) The decimal numbers to allow the REM units to grow to.
viewportUnit: 'vw', // (String) Expected units.
selectorBlackList: ['.ignore', '.hairlines'], // (Array) The selectors to ignore and leave as px.
minPixelValue: 1, // (Number) Set the minimum pixel value to replace.
mediaQuery: false, // (Boolean) Allow px to be converted in media queries.
}),
require('postcss-write-svg')({
utf8: false,
}),
require('postcss-cssnext'),
require('postcss-viewport-units'),
require('cssnano')({
preset: 'advanced',
autoprefixer: false,
'postcss-zindex': false,
}),
],
},
options: {},
},
],
});
......
......@@ -26,7 +26,12 @@
"autoprefixer": "^9.1.0",
"babel-plugin-import": "^1.8.0",
"cssnano-preset-advanced": "^4.0.0",
"less": "^3.8.1",
"less-loader": "^4.1.0",
"postcss-import": "^12.0.0",
"postcss-load-config": "^2.0.0",
"postcss-plugin": "^1.0.0",
"postcss-url": "^7.3.2",
"react-app-rewired": "^1.5.2"
},
"browserslist": [
......
......@@ -6,6 +6,17 @@ export const sendMsg = entity =>
url: '/login/sendMsg',
params: entity,
});
// base
export const fetchRepairArea = () =>
fetch({
url: '/baseData/getBaseData',
params: { type: 1 },
});
export const fetchRepairTerm = () =>
fetch({
url: '/baseData/getBaseData',
params: { type: 2 },
});
// publicCar
export const fetchPublicCarList = entity =>
fetch({
......
import React, { Component } from 'react';
import styles from './style.css';
import addimgIcon from './images/add_pic_bg@2x.png';
import delIcon from './images/delete_pic_btn@2x.png';
class ImagePicker extends Component {
constructor(props) {
super(props);
this.state = {
done: false,
files: [],
};
}
selectImage = () => {
const { done } = this.state;
if (done) {
console.log('showView');
} else {
this.refs.input.dispatchEvent(new MouseEvent('click'));
}
};
deleteImage = e => {
e.stopPropagation();
console.log('del');
this.refs.input.value = '';
this.setState(() => ({
files: [],
done: false,
}));
};
uploadImg = e => {
const filesList = e.target.files;
console.log(filesList);
const fileUrl = this.createObjectURL(filesList[0]);
this.setState(() => ({
files: [fileUrl],
done: true,
}));
};
createObjectURL = blob => {
if (window.URL) {
return window.URL.createObjectURL(blob);
} else if (window.webkitURL) {
return window.webkitURL.createObjectURL(blob);
}
return null;
};
revokeObjectURL = url => {
if (window.URL) {
return window.URL.revokeObjectURL(url);
} else if (window.webkitURL) {
return window.webkitURL.revokeObjectURL(url);
}
};
render() {
const { className } = this.props;
const { files, done } = this.state;
return (
<div
className={
className ? `${className} ${styles.imageWrap}` : styles.imageWrap
}
onClick={this.selectImage}
>
{done ? (
<img className={styles.innerImg} src={files[0]} alt="" />
) : (
<img src={addimgIcon} alt="" />
)}
{done && (
<img
src={delIcon}
className={styles.delBtn}
alt=""
onClick={this.deleteImage}
/>
)}
<input
ref="input"
type="file"
accept="image/*"
onChange={this.uploadImg}
style={{ display: 'none' }}
/>
</div>
);
}
}
export default ImagePicker;
.imageWrap {
width: 170px;
height: 96px;
/* background-image: url('./images/add_pic_bg@2x.png'); */
position: relative;
}
.innerImg {
width: 100%;
height: 100%;
}
.delBtn {
position: absolute;
width: 38px;
height: 38px;
left: 50%;
top: 76px;
transform: translate(-50%, 0);
}
import React, { Component } from 'react';
import styles from './style.css';
class Radio extends Component {
constructor(props) {
super(props);
this.state = {
};
}
render() {
return (
<label className={styles.radioBox}>
<span className={styles.radio}>
<span className={styles.radioInner} />
<input type="radio" className={styles.radioInput} />
</span>
{this.props.children}
</label>
);
}
}
export default Radio;
.radioBox {
}
.radio {
position: relative;
display: inline-block;
vertical-align: middle;
width: 30px;
height: 30px;
border: 1px solid #ccc;
border-radius: 50%;
margin-right: 10px;
}
.radioInner {
position: absolute;
right: 0;
width: 15px;
height: 15px;
-webkit-box-sizing: border-box;
box-sizing: border-box;
-webkit-transform: rotate(0deg);
-ms-transform: rotate(0deg);
transform: rotate(0deg);
}
.radioInput {
position: absolute;
top: 0;
left: 0;
opacity: 0;
width: 100%;
height: 100%;
z-index: 2;
border: 0 none;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
}
import React, { Component } from 'react';
import ReactDom from 'react-dom';
import styles from './style.css';
import arrIcon from './images/select_icon@2x.png';
import { PickerView } from 'antd-mobile';
class Select extends Component {
showPickerView = () => {
console.log('showPickerView');
let box = document.getElementById('ks-picker-box');
if (box) {
ReactDom.render(<PickerView />, box);
} else {
let box = document.createElement('div');
document.body.appendChild(box);
ReactDom.render(<PickerView />, box);
}
};
render() {
const { placeholder } = this.props;
return (
<div className={styles.selectWrap} onClick={this.showPickerView}>
{placeholder ? placeholder : ''}
<span className={styles.arrow}>
<img src={arrIcon} alt="" />
</span>
</div>
);
}
}
export default Select;
.selectWrap {
position: relative;
color: #666;
}
.arrow {
position: absolute;
right: 0;
bottom: 0;
width: 24px;
height: 24px;
}
import React, { Component } from 'react';
import styles from './style.css';
import { Radio, Toast, Button, TextareaItem } from 'antd-mobile';
import peopleIcon from './images/repair_people_icon@2x.png';
import phoneIcon from './images/phone_tel_icon@2x.png';
import roleIcon from './images/user_role_icon@2x.png';
......@@ -7,9 +8,96 @@ import areaIcon from './images/repair_area_icon@2x.png';
import typeIcon from './images/repair_item_icon@2x.png';
import addrIcon from './images/repair_addr_icon@2x.png';
import imgIcon from './images/upload_pic_icon@2x.png';
import ImagePicker from '../../components/Input/ImagePicker/ImagePicker';
import Select from '../../components/Input/Select/Select';
import { fetchRepairArea, fetchRepairTerm } from '../../api/index';
class ReprtRepair extends Component {
constructor(props) {
super(props);
this.state = {
areaList: [],
termList: [],
applyForm: {
name: '',
userId: '',
repairCellphone: '',
applyIdentity: '学生',
area: '',
areaId: '',
term: '',
termId: '',
address: '',
uploadImg: [],
},
};
}
componentDidMount() {
fetchRepairArea()
.then(res => {
this.setState(() => ({
areaList: res.data,
}));
})
.catch(err => {
console.log(err);
});
fetchRepairTerm()
.then(res => {
this.setState(() => ({
termList: res.data,
}));
})
.catch(err => {
console.log(err);
});
}
onChangeHandle = e => {
const { name, value } = e.target;
this.setState(({ applyForm }) => ({
applyForm: {
...applyForm,
[name]: value,
},
}));
};
validateForm = () => {
const { applyForm } = this.state;
if (!applyForm.name) {
Toast.fail('请输入报修人!');
return;
}
if (!applyForm.repairCellphone) {
Toast.fail('请输入报修人电话!');
return;
}
if (!applyForm.applyIdentity) {
Toast.fail('请选择报修人身份!');
return;
}
if (!applyForm.areaId) {
Toast.fail('请选择报修区域!');
return;
}
if (!applyForm.termId) {
Toast.fail('请选择报修项目!');
return;
}
if (!applyForm.address) {
Toast.fail('请输入报修地址!');
return;
}
return true;
};
startApply = () => {
if (!this.validateForm()) {
return;
}
};
render() {
const { applyForm } = this.state;
return (
<div className={styles.wrap}>
<div className={styles.listItem}>
......@@ -18,7 +106,14 @@ class ReprtRepair extends Component {
</i>
<span className={styles.itemLabel}>报修人</span>
<div className={styles.inputBox}>
<input className={styles.input} type="text" />
<input
className={styles.input}
type="text"
maxLength="20"
name="name"
value={applyForm.name}
onChange={this.onChangeHandle}
/>
</div>
</div>
<div className={styles.listItem}>
......@@ -27,7 +122,14 @@ class ReprtRepair extends Component {
</i>
<span className={styles.itemLabel}>报修人tel</span>
<div className={styles.inputBox}>
<input className={styles.input} type="text" />
<input
className={styles.input}
type="tel"
maxLength="11"
name="repairCellphone"
value={applyForm.repairCellphone}
onChange={this.onChangeHandle}
/>
</div>
</div>
<div className={styles.listItem}>
......@@ -35,8 +137,27 @@ class ReprtRepair extends Component {
<img src={roleIcon} alt="" />
</i>
<span className={styles.itemLabel}>报修身份</span>
<div className={styles.inputBox}>
<input className={styles.input} type="text" />
<div className={styles.inputBoxNoBB}>
{/* <input className={styles.input} type="text" /> */}
<Radio
className="my-radio"
name="applyIdentity"
value="老师"
checked={applyForm.applyIdentity === '老师'}
onChange={this.onChangeHandle}
>
老师
</Radio>
<Radio
className="my-radio"
name="applyIdentity"
value="学生"
checked={applyForm.applyIdentity === '学生'}
onChange={this.onChangeHandle}
>
学生
</Radio>
</div>
</div>
<div className={styles.listItem}>
......@@ -45,7 +166,10 @@ class ReprtRepair extends Component {
</i>
<span className={styles.itemLabel}>报修区域</span>
<div className={styles.inputBox}>
<input className={styles.input} type="text" />
{/* <Picker data={areaList}>
<List.Item arrow="horizontal" onClick={this.onClick} />
</Picker> */}
<Select placeholder="请选择" />
</div>
</div>
<div className={styles.listItem}>
......@@ -63,12 +187,26 @@ class ReprtRepair extends Component {
</i>
<span className={styles.itemLabel}>报修地址</span>
</div>
<TextareaItem
className="textarea"
placeholder="输入报修地址"
rows={3}
count={50}
/>
<div className={styles.listItem}>
<i className={styles.itemIcon}>
<img src={imgIcon} alt="" />
</i>
<span className={styles.itemLabel}>上传图片</span>
</div>
<div className={styles.imageArea}>
<ImagePicker />
<ImagePicker />
<ImagePicker />
</div>
<Button className={styles.applyBtn} onClick={this.startApply}>
提交
</Button>
</div>
);
}
......
import React, { Component } from 'react';
import { Switch, Route, Redirect } from 'react-router-dom';
import { Switch, Route, Redirect, NavLink } from 'react-router-dom';
import styles from './style.css';
import ReprtRepair from './ReprtRepair';
import RepairList from './RepairList';
......@@ -17,7 +17,6 @@ class index extends Component {
history.replace('/repair/' + name);
};
render() {
const { tab } = this.state;
return (
<div className="Content-Wrap">
<div className={styles.content}>
......@@ -28,23 +27,13 @@ class index extends Component {
</Switch>
</div>
<div className={styles.footer}>
<span
className={`${[styles['footer-item']]} ${
tab === 'ReprtRepair' ? styles.activated : ''
}`}
onClick={() => this.toggleRouteHandle('ReprtRepair')}
>
<NavLink className={styles['footer-item']} to="/repair/ReprtRepair">
报修服务
</span>
<span className={styles.line}></span>
<span
className={`${[styles['footer-item']]} ${
tab === 'RepairList' ? styles.activated : ''
}`}
onClick={() => this.toggleRouteHandle('RepairList')}
>
</NavLink>
<span className={styles.line} />
<NavLink className={styles['footer-item']} to="/repair/RepairList">
报修记录
</span>
</NavLink>
</div>
</div>
);
......
/* index */
.content {
flex: auto;
overflow-y: scroll;
}
.footer {
width: 100%;
......@@ -10,7 +11,6 @@
justify-content: center;
align-items: center;
font-size: 30px;
color: #999;
}
.line {
width: 2px;
......@@ -18,24 +18,24 @@
background-color: #f0f0f0;
}
.footer-item {
margin: 0 80px;
flex: 1;
color: #999;
text-align: center;
}
.activated {
color: #3695c0;
:global(.active) {
background-color: #3695c0;
color: #fff;
}
/* Report */
.wrap {
width: 100%;
height: 100%;
overflow-y: scroll;
padding-bottom: 20px;
}
.listItem {
margin-top: 32px;
height: 48px;
line-height: 48px;
display: flex;
align-items: center;
padding: 0 40px;
padding: 32px 40px 0;
}
.itemIcon {
width: 30px;
......@@ -54,6 +54,7 @@
.inputBox {
position: relative;
flex: auto;
text-align: center;
}
.input {
border: none;
......@@ -79,3 +80,102 @@
transform-origin: 50% 100%;
transform: scaleY(0.5);
}
.inputBoxNoBB {
composes: inputBox;
}
.inputBoxNoBB::after {
display: none;
}
:global(.my-radio) {
color: #666;
margin-right: 20px;
}
:global(.my-radio .am-radio) {
box-sizing: border-box;
width: 30px;
height: 30px;
border: 1px solid #666;
border-radius: 50%;
margin-right: 10px;
}
:global(.my-radio .am-radio-inner) {
width: 30px;
height: 30px;
left: 0;
top: 0;
}
:global(.my-radio .am-radio-inner::after) {
content: '';
width: 15px;
height: 15px;
top: 5px;
left: 5px;
background-color: #3695c0;
border-radius: 50%;
}
.radio {
position: relative;
display: inline-block;
vertical-align: middle;
width: 30px;
height: 30px;
border: 1px solid #ccc;
border-radius: 50%;
margin-right: 10px;
}
.radioInner {
position: absolute;
right: 0;
width: 15px;
height: 15px;
box-sizing: border-box;
transform: rotate(0deg);
}
.radioInput {
position: absolute;
top: 0;
left: 0;
opacity: 0;
width: 100%;
height: 100%;
z-index: 2;
border: 0 none;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
}
:global(.textarea) {
background-color: #f0f0f0;
border-radius: 8px;
width: 560px;
height: 150px;
line-height: 30px;
margin: 0px auto 0;
color: #666;
padding: 16px 20px 0;
}
:global(.textarea .am-textarea-control) {
padding: 0;
}
:global(.am-textarea-item .am-textarea-control textarea) {
font-size: 26px;
color: #666;
}
.imageArea {
display: flex;
justify-content: space-between;
width: 560px;
margin: 0 auto;
padding-bottom: 18px;
}
.applyBtn {
height: 80px;
line-height: 80px;
width: 560px;
margin: 20px auto 0;
color: #fff;
font-size: 30px;
font-weight: bold;
background-color: #3695c0;
}
......@@ -105,4 +105,5 @@ img {
height: 100%;
display: flex;
flex-direction: column;
overflow: hidden;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment