Commit 8fb450c1 by peii

添加typescript支持

parent 34bf3598
Showing with 10875 additions and 18 deletions
......@@ -5,13 +5,24 @@
* @format
*/
module.exports = {
transformer: {
getTransformOptions: async () => ({
transform: {
experimentalImportSupport: false,
inlineRequires: false,
},
}),
},
};
const { getDefaultConfig } = require('metro-config')
module.exports = (async () => {
const {
resolver: { sourceExts },
} = await getDefaultConfig()
return {
transformer: {
babelTransformerPath: require.resolve('react-native-stylus-transformer'),
getTransformOptions: async () => ({
transform: {
experimentalImportSupport: false,
inlineRequires: false,
},
}),
},
resolver: {
sourceExts: [...sourceExts, 'styl'],
},
}
})()
......@@ -45,7 +45,19 @@
"jetifier": "^1.6.6",
"metro-react-native-babel-preset": "^0.54.1",
"react-native-gesture-handler": "1.0.5",
"react-test-renderer": "16.8.3"
"react-test-renderer": "16.8.3",
"@babel/plugin-transform-runtime": "^7.13.10",
"@types/jest": "^26.0.22",
"@types/ramda": "^0.27.39",
"@types/react": "^17.0.3",
"@types/react-native": "^0.64.2",
"@types/react-test-renderer": "^17.0.1",
"babel-plugin-module-resolver": "^4.1.0",
"react-native-postcss-transformer": "^1.2.4",
"react-native-stylus-transformer": "^1.2.0",
"reflect-metadata": "^0.1.13",
"stylus": "^0.54.8",
"typescript": "^4.2.4"
},
"jest": {
"preset": "react-native"
......
@import './variable.styl'
.container
flex 1
.row
flex-direction row
.center
align-items center
.middle
justify-content center
.icon
resizeMode cover
width 100%
height 100%
hToR($color, opacity = 1)
return rgba(red($color), green($color), blue($color), opacity)
.bg-gray
background-color home_background_color
.animated
animation-duration 1s
animation-fill-mode both
@keyframes slide-up
from
// -webkit-transform translate3d(0, 100%, 0)
// transform translate3d(0, 100%, 0)
translateY 100%
visibility visible
to
// -webkit-transform translate3d(0, 0, 0)
// transform translate3d(0, 0, 0)
translateY 0
/*
* @FilePath: /BoneHouse_Hospital_APP/src/assets/styles/base.ts
* @Author: peii
* @Date: 2021-04-24 22:45:15
* @Vision: 1.0
* @Description:
*
* @Revision:
*
*/
import {
Dimensions
} from 'react-native'
const { width, height } = Dimensions.get('window');
export const getHeight = () => {
return height
};
export const getWidth = () => {
return width
};
// UI 默认图是414*896
const uiWidthPx = 414;
const uiHeightPx = 896;
export function pxSize(uiElementPx) {
return uiElementPx * getWidth() / uiWidthPx;
}
export function pxHeight(uiElementPx) {
return uiElementPx * getHeight() / uiHeightPx;
}
// 背景色
export const primary_color = "#20BEB8"; // 主色
export const foundation_color = "#ffffff"; // 底色
export const promary_shadow_color = "#3CA2FF"; // 按钮阴影色
export const home_background_color = "#F7F7F7"; // 背景色
export const btn_sub_color = "#20BEB8"; // 按钮色
export const dis_sub_color = "#BBBBBB"; // 禁用按钮色
// 字体色
export const primary_text_color = "#000000"; // 主字颜色
export const title_text_color = "#ffffff"; // 标题颜色
export const placehold_text_color = "#919191"; // input placeholder颜色
export const first_text_color = '#333333'; // 一级字体
export const second_text_color = "#666666"; // 次级字体
export const third_text_color = "#999999"; // 三级字体
export const point_color = "#ff0000"; // * 颜色
export const text_default_color = "#01B2B9"; // 默认颜色
export const text_audit_color = "#FF0000"; // 拒绝颜色
export const text_return_color = "#007EFF"; // 归还颜色
export const text_other_color = "#F4B61B"; // 其他颜色
export const list_tit_color = 'rgba(0, 0, 0, 0.87)'; // 列表标题颜色
export const list_str_color = "#0CB4E8"; // 列表加粗颜色
export const list_one_color = "#1B40B5"; // 列表一级颜色
export const list_thr_color = "#3B4C82"; // 列表其他颜色
export const list_one_light_color = "#3c64e2"; // 列表一级较浅颜色
// 字号
export const first_text_size = 20; // 一级字号
export const second_text_size = 16; // 二级字号
export const third_text_size = 12; // 三级字号
// 字体样式
export const font_family_semibold = "PingFangSC-Semibold";
export const font_family_medium = "PingFangSC-Medium";
export const font_family_regular = "PingFangSC-Regular";
export const font_family_light = "PingFangSC-Light";
export const header_height = 58
export const icon_style = {
resizeMode: 'cover',
width: '100%',
height: '100%'
}
export const safe_view = {
flex: 1
}
// 背景色
primary_color = #20BEB8// 主色
foundation_color = #ffffff // 底色
promary_shadow_color = #20BEB8// 按钮阴影色
home_background_color = #F7F7F7 // 背景色
btn_sub_color = #20BEB8 // 按钮色
dis_sub_color = #BBBBBB // 禁用按钮色
input_background_color = #efefef // 输入框底色
btn_color = #ffffff // 按钮字体颜色
// 字体色
primary_text_color = #000000 // 主字颜色
title_text_color = #ffffff // 标题颜色
placehold_text_color = #919191 // input placeholder颜色
first_text_color = #333333 // 一级字体
second_text_color = #666666 // 次级字体
third_text_color = #999999 // 三级字体
point_color = #ff0000 // * 颜色
text_default_color = #01B2B9 // 默认颜色
text_audit_color = #FF0000 // 拒绝颜色
text_return_color = #007EFF // 归还颜色
text_other_color = #F4B61B // 其他颜色
list_tit_color = rgba(0, 0, 0, 0.87) // 列表标题颜色
list_str_color = #0CB4E8 // 列表加粗颜色
list_one_color = #1B40B5 // 列表一级颜色
list_thr_color = #3B4C82 // 列表其他颜色
list_one_light_color = #3c64e2 // 列表一级较浅颜色
// 字号
first_text_size = 20px // 一级字号
second_text_size = 16px // 二级字号
third_text_size = 12px // 三级字号
// 字体样式
font_family_semibold = 'PingFangSC-Semibold'
font_family_medium = 'PingFangSC-Medium'
font_family_regular = 'PingFangSC-Regular'
font_family_light = 'PingFangSC-Light'
header_height = 66.5px
import React, { Component, PropTypes } from 'react'
import { Dimensions, Platform, PixelRatio, StatusBar, View, ScrollView } from 'react-native'
let props = {}
/**
* UI兼容类,把最外层的的组件使用这个类包起来,后续开发可以直接使用设计稿去开发
*/
export default class Resolution {
static get(useFixWidth = true) {
return useFixWidth ? { ...props.fw } : { ...props.fh }
}
static setDesignSize(dWidth = 414, dHeight = 896, dim = 'window'): void {
let designSize = { width: dWidth, height: dHeight }
// let navHeight = Platform.OS === 'android' ? StatusBar.currentHeight : 64
let navHeight = 0
let pxRatio = PixelRatio.get()
let { width, height } = Dimensions.get(dim)
if (dim != 'screen') height -= navHeight
let w = PixelRatio.getPixelSizeForLayoutSize(width)
let h = PixelRatio.getPixelSizeForLayoutSize(height)
let fwDesignScale = designSize.width / w
let fwWidth = designSize.width
let fwHeight = h * fwDesignScale
let fwScale = 1 / pxRatio / fwDesignScale
let fhDesignScale = designSize.height / h
let fhWidth = w * fhDesignScale
let fhHeight = designSize.height
let fhScale = 1 / pxRatio / fhDesignScale
props.fw = { width: fwWidth, height: fwHeight, scale: fwScale, navHeight }
props.fh = { width: fhWidth, height: fhHeight, scale: fhScale, navHeight }
}
static FixWidthView(p) {
let { width, height, scale, navHeight } = props.fw
return (
<View
{...p}
style={{
marginTop: navHeight,
width: width,
height: height,
backgroundColor: 'transparent',
transform: [
{ translateX: -width * 0.5 },
{ translateY: -height * 0.5 },
{ scale: scale },
{ translateX: width * 0.5 },
{ translateY: height * 0.5 },
],
}}
>
{p.children}
</View>
)
}
static FixHeightView(p) {
let { width, height, scale, navHeight } = props.fh
return (
<View
{...p}
style={{
marginTop: navHeight,
// width: width,
height: height,
backgroundColor: 'transparent',
transform: [
{ translateX: -width * 0.5 },
{ translateY: -height * 0.5 },
{ scale: scale },
{ translateX: width * 0.5 },
{ translateY: height * 0.5 },
],
}}
>
{p.children}
</View>
)
}
}
Resolution.setDesignSize()
@import '../../assets/styles/base.styl'
@import '../../assets/styles/variable.styl'
.checkbox
&-inner
@extend .row
margin-right 10px
&__box
width 25px
height @width
border-radius 13.5px
border 1px solid #ccc
&-img
width 25px
height 25px
&-active
border-color transparent
import React, { Component } from 'react'
import { View, Text, TouchableWithoutFeedback, Image } from 'react-native'
import * as R from 'ramda'
import { isBlank, g, isNotBlank } from '../../utils/utils'
import styles from './checkbox.styl'
type IProps = {
checked: boolean
label?: string
onChange: Function
}
export default ({ checked, label, onChange, style }: Iprops) => {
return (
<TouchableWithoutFeedback
style={g(styles, 'checkbox')}
onPress={() => {
onChange && onChange(!checked)
}}
>
<View style={[g(styles, 'checkbox-inner'), style]}>
<View
style={g(styles, { 'checkbox-inner__box': true, 'checkbox-inner__box-active': checked })}
>
{!!checked && (
<Image
source={require('../../assets/images/ic_checked_blue.png')}
style={g(styles, 'checkbox-inner__box-img')}
/>
)}
</View>
{isNotBlank(label) && <Text>{label}</Text>}
</View>
</TouchableWithoutFeedback>
)
}
@import '../../assets/styles/base.styl'
@import '../../assets/styles/variable.styl'
.empty
flex 1
@extend .middle
@extend .center
padding-top 30px
&-icon
width 80px
height 75px
&-text
font-size 20px
color second_text_color
margin-top 20px
font-family font_family_regular
/*
* @FilePath: /BoneHouse_Hospital_APP/src/components/empty/index.tsx
* @Author: peii
* @Date: 2021-05-30 17:04:50
* @Vision: 1.0
* @Description: 加载
*
* @Revision:
*
*/
import React, { Component } from 'react'
import { View, Text, Image } from 'react-native'
import { g } from '../../utils/utils'
import styles from './index.styl'
export default ({ text = '暂无数据', style }) => {
return (
<View style={[g(styles, 'empty'), style]}>
<Image style={[g(styles, 'empty-icon')]} source={require('../../assets/images/mail_empty.png')} />
<Text style={[g(styles, 'empty-text')]}>{text}</Text>
</View>
)
}
import React, { Component } from 'react'
import { View, Text, Image, TouchableOpacity, TextInput } from 'react-native'
import { IFormField } from 'bonehouse'
import { g, isRequired } from '../../utils/utils'
import styles from './index.styl'
export const Title = props => {
const { item } = props
const required = isRequired(item)
return (
<Text style={g(styles, 'form-label')}>
{!!required && <Text style={g(styles, 'red', 'pr5')}>*</Text>}
<Text>{item.label}</Text>
</Text>
)
}
@import '../../assets/styles/base.styl'
@import '../../assets/styles/variable.styl'
.modal
&-hd
height 50px
padding 15px 20px
&__btns
flex-direction row
justify-content space-between
&-btn
color btn_sub_color
font-size second_text_size
&-bd
height 100%
align-items center
/*
* @FilePath: /BoneHouse_Hospital_APP/src/components/form/date-modal.tsx
* @Author: peii
* @Date: 2021-04-27 21:53:02
* @Vision: 1.0
* @Description: 选择组件的弹出框
*
*
*/
// @ts-nocheck
import React, { useEffect, useRef, useState, createRef } from 'react'
import { View, Text, TouchableOpacity, ScrollView, Animated } from 'react-native'
import DatePicker from 'react-native-date-picker'
import { IFormField } from 'bonehouse'
import * as R from 'ramda'
import dayjs from 'dayjs'
import { isBlank } from '../../utils/utils'
import { BottomModal } from '../modals/base/bottom'
import { FieldType } from '../../enums'
import { g } from '../../utils/utils'
import styles from './date-modal.styl'
type IModalProps = {
value: string | number
mask?: boolean
title?: string
visible: boolean
onChange?: Function
onClose: Function
item?: IFormField
}
/**
* @description: 选择器弹窗
* @param {IModalProps} props
* @return {*}
*/
export function DateModal(props: IModalProps) {
const { item, value, mask, onChange, visible, onClose } = props
const [contentHeight, setContentHeight] = useState(300)
const [dateValue, setDateValue] = useState(value)
const [action, setAction] = useState(0)
return (
<BottomModal contentHeight={contentHeight} visible={visible} onClose={onClose} action={action}>
<View style={g(styles, ['modal-hd', 'modal-hd__btns'])}>
<TouchableOpacity
activeOpacity={0.8}
onPress={() => {
// animated(bottom, -contentHeight, opacity, 0, onClose)
// onClose()
setAction(action + 1)
}}
>
<Text style={g(styles, 'modal-hd__btns-btn')}>取消</Text>
</TouchableOpacity>
<TouchableOpacity
activeOpacity={0.8}
onPress={() => {
const date = dateValue || value
onChange(dayjs(date).format('YYYY-MM-DD HH:mm'))
setAction(action + 1)
}}
>
<Text style={g(styles, 'modal-hd__btns-btn')}>确定</Text>
</TouchableOpacity>
</View>
<View style={g(styles, 'modal-bd')}>
<DatePicker
date={dayjs(dateValue).toDate() || dayjs().toDate()}
mode={item.dateMode || 'date'}
locale="zh"
minuteInterval={item.minuteInterval || 30}
onDateChange={date => {
setDateValue(date)
}}
/>
</View>
</BottomModal>
)
}
/*
* @FilePath: /BoneHouse_Hospital_APP/src/components/form/date.tsx
* @Author: peii
* @Date: 2021-04-25 23:36:10
* @Vision: 1.0
* @Description: 选择器组件
*
* @Revision:
*
*/
import React, { Component } from 'react'
import { View, Text, Image, TouchableOpacity } from 'react-native'
import { IFormField, IOption } from 'bonehouse'
import * as R from 'ramda'
import { isBlank, show, isNotBlank, g } from '../../utils/utils'
import { FieldType } from '../../enums'
import { Title } from './common'
import { DateModal } from './date-modal'
import styles from './index.styl'
type IProps = {
item: IFormField
value: any
onChange: Function
data: any
fields: any[]
modalCallback: Function
}
/**
* @description: 获取显示字符
* @param {*} item
* @param {*} val
* @return {*}
*/
const getText = (item, val) => {
if (!val) return null
return R.compose(R.find(R.propEq('value', val)), R.propOr([], 'options'))(item)
}
export default class DatePicker extends Component<IProps> {
state = {
visible: false,
}
constructor(props) {
super(props)
this.onPressHandler = this.onPressHandler.bind(this)
this.onChange = this.onChange.bind(this)
}
shouldComponentUpdate(nextProps: IProps) {
return true
}
componentWillReceiveProps(nextProps, nextState) {
const { item, value } = nextProps
const { visible } = this.state
}
/**
* @description: 点击显示行
*/
onPressHandler() {
const { item, data, fields, value } = this.props
if (item.disabled) return
// 需要先选择依赖的字段
for (const ref of item.refrence || []) {
if (isBlank(data[ref])) {
const field = R.find(R.propEq('field', ref))(fields)
if (isNotBlank(field)) {
return show(`请先选择${field.label}`)
}
}
}
this.setState({ visible: true }, () => {
const modal = (
<DateModal
item={item}
value={value}
visible={true}
mask={true}
onChange={this.onChange}
onClose={() => {
this.setState({ visible: false }, () => {
this.props.modalCallback()
})
}}
/>
)
this.props.modalCallback(modal)
})
}
/**
* @description: 点击弹出选中值
*/
onChange(val: any): void {
const { item, value } = this.props
if (val === value) return
this.props && this.props.onChange(item.field, val, item.callback)
}
render() {
const { visible } = this.state
const { item, value } = this.props
return (
<>
<TouchableOpacity
style={g(styles, 'form-item')}
activeOpacity={item.disabled ? 1 : 0.8}
onPress={this.onPressHandler}
>
<Title item={item} />
<View style={g(styles, 'form-input')}>
{/* 值 */}
{isBlank(value) ? (
<Text style={g(styles, 'form-input__placeholder')}>{item.placeholder || '请选择'}</Text>
) : (
<Text numberOfLines={2} style={g(styles, 'form-input__text')}>
{value}
</Text>
)}
{/* 箭头 */}
{item.arrow !== false && (
<Image source={require('../../assets/images/arr_rig.png')} style={g(styles, 'form-input__arrow')} />
)}
</View>
</TouchableOpacity>
</>
)
}
}
@import '../../assets/styles/base.styl'
@import '../../assets/styles/variable.styl'
.image
margin-bottom 20px
&-title
color rgba(182, 182, 182, 100)
font-size 17px
font-family font_family_regular
margin-bottom 10px
&-bd
width 378px
height 172px
background-color rgba(255, 255, 255, 1)
padding 16px
&__inner
width 378px
flex-direction row
flex-wrap wrap
padding-bottom 16px
&-box
width 56px
height @width
border-radius 6px
background-color rgba(255, 255, 255, 1)
border 1px solid rgba(221, 221, 221, 1)
margin-bottom 15px
margin-right 15px
@extend .center
@extend .middle
&__remove
position absolute
right -10px
top -10px
&-icon
width 20px
height @width
&__touch
width 54px
height 54px
&-plus
font-size 50px
line-height 54px
color rgba(221, 221, 221, 1)
font-weight 200
&-img
width 54px
height 54px
border-radius 6px
import React, { Component } from 'react'
import {
View,
Text,
Image,
TouchableOpacity,
ScrollView,
Alert,
Linking,
Platform,
} from 'react-native'
import { IFormField, IOption } from 'bonehouse'
import * as R from 'ramda'
import ImagePicker from 'react-native-image-picker'
import Toast, { Positions } from 'react-native-root-toast'
import { isBlank, show, isRequired, isNotBlank, g } from '../../utils/utils'
import styles from './image.styl'
// import Container from '../../inversify'
// import { TYPES } from '../../inversify/types'
// import Service from '../../services/service'
// const service: Service = Container.get(TYPES.Service)
type IProps = {
item: IFormField
value: string[]
onChange: Function
}
export default class ImageForm extends React.Component<IProps> {
state = {
options: {
title: '选择图片',
cancelButtonTitle: '取消',
takePhotoButtonTitle: '拍照',
chooseFromLibraryButtonTitle: '相册',
cameraType: 'back',
mediaType: 'photo',
videoQuality: 'high',
durationLimit: 10,
maxWidth: 720,
maxHeight: 1280,
aspectX: 2,
aspectY: 1,
quality: 1,
angle: 0,
allowsEditing: false,
noData: false,
storageOptions: {
skipBackup: true,
path: 'Wisdom', // 存储本地地址
},
},
urls: [],
}
constructor(props) {
super(props)
this.onPickImageHandler = this.onPickImageHandler.bind(this)
}
/**
* @description: 点击添加图标
* @param {*}
* @return {*}
*/
onPickImageHandler() {
const { options } = this.state
ImagePicker.showImagePicker(options, async res => {
if (res.didCancel) return
if (res.error) {
const errMsgs = ['Camera permissions not granted', 'Photo library permissions not granted']
const errTips = [
'APP需要使用相机,请打开相机权限允许APP使用',
'APP需要使用相册,请打开相册权限允许APP使用',
]
for (const [idx, msg] of Object.entries(errMsgs)) {
if (R.indexOf(res.error, msg) > -1) {
Alert.alert('提示信息', errTips[idx], [
{
text: '设置',
onPress: () => {
Linking.openURL('app-settings:').catch(err => console.log('error', err))
},
},
{
text: '取消',
},
])
return
}
}
return show(res.error)
}
let source = res.uri
if (Platform.OS === 'ios') {
source = res.uri.replace('file://', '')
!res.fileName && (res.fileName = new Date().getTime() + '.heic')
}
const formData = new FormData()
let file = { uri: source, type: 'multipart/form-data', name: res.fileName }
formData.append('file', file)
try {
const loading = Toast.show('上传中', { duration: 60000, position: Toast.positions.CENTER })
// const result = await service.uploadImg(formData)
Toast.hide(loading)
let value = this.props.value || []
value = R.append(result.data.url, value)
this.props.onChange(this.props.item.field, value)
let { urls } = this.state
urls = R.append(source, urls)
this.setState({ urls })
} catch (error) {
Toast.hide(loading)
}
})
}
/**
* @description: 删除单项
* @param {*} idx
* @return {*}
*/
removeHandler(idx) {
let { value, onChange, item } = this.props
let { urls } = this.state
urls = R.remove(idx, 1, urls)
value = R.remove(idx, 1, value)
this.setState({ urls })
onChange && onChange(item.field, value)
}
render() {
const { item, value } = this.props
const { urls } = this.state
return (
<View style={g(styles, 'image')}>
<Text style={g(styles, 'image-title')}>{item.label}</Text>
<ScrollView style={g(styles, 'image-bd')}>
<View style={g(styles, 'image-bd__inner')}>
{isNotBlank(urls) &&
urls.map((url, idx) => {
return (
<View style={g(styles, 'image-box')} key={url}>
<TouchableOpacity style={g(styles, 'image-box__touch')}>
<Image source={{ uri: url }} style={g(styles, 'image-img')} />
</TouchableOpacity>
<TouchableOpacity
style={g(styles, 'image-box__remove')}
onPress={() => {
this.removeHandler(idx)
}}
>
<Image
source={require('../../assets/images/close_err_icon.png')}
style={g(styles, 'image-box__remove-icon')}
/>
</TouchableOpacity>
</View>
)
})}
<TouchableOpacity
style={g(styles, 'image-box')}
activeOpacity={0.7}
onPress={() => {
this.onPickImageHandler()
}}
>
<Text style={g(styles, 'image-plus')}>+</Text>
</TouchableOpacity>
</View>
</ScrollView>
</View>
)
}
}
@import '../../assets/styles/base.styl'
@import '../../assets/styles/variable.styl'
.text
font-size second_text_size
font-family font_family_regular
.container
flex 1
.form
flex 1
&-inner
padding 18px
width 100%
height 100%
&-item
width 378px
height 58px
background-color #fff
padding 0 18px
flex-direction row
justify-content space-between
align-items center
margin-bottom 18px
&-multi
height 160px
padding 18px
flex-direction column
align-items flex-start
&-label
@extend .text
color primary_text_color
width 120px
&-input
flex-direction row
align-items center
justify-content flex-end
flex 1
&__placeholder
@extend .text
color placehold_text_color
&__text
@extend .text
color second_text_color
line-height 18px
text-align right
&__arrow
width 8px
height 14px
margin-left 9px
&-text-input
@extend .text
text-align right
color second_text_color
&__multi
text-align left
&-radio
flex 1
@extend .row
justify-content flex-end
&__item
@extend .row
align-items center
padding-left 20px
&-box
margin-right 8px
width 20px
height @width
border-color #ccc
border-width 1px
border-radius 10px
&-image
width 18px
height @width
&-text
@extend .text
color second_text_color
.red
color #f00
.submit-btn
width 343px
height 52px
border-radius 9px
background-color primary_color
justify-content center
align-items center
align-self center
margin-bottom 30px
&__inner
@extend .row
&__disabled
background-color #BBBBBB
&__text
color rgba(255, 255, 255, 100)
font-size 17px
font-family font_family_semibold
&__disabled
color rgba(255, 255, 255, 0.5)
.ml10
margin-left 10px
/*
* @FilePath: /BoneHouse_Hospital_APP/src/components/form/index.tsx
* @Author: peii
* @Date: 2021-04-25 22:40:31
* @Vision: 1.0
* @Description: 基础表单组件
*
* @Revision:
*
*/
// @ts-nocheck
import React, { Component } from 'react'
import {
View,
Text,
ScrollView,
SafeAreaView,
TouchableOpacity,
ActivityIndicator,
KeyboardAvoidingView,
} from 'react-native'
import { IFormField } from 'bonehouse'
import * as R from 'ramda'
import { FieldType } from '../../enums'
import Select from './select'
import Radio from './radio'
import Input from './input'
import DatePicker from './date'
import ImageForm from './image'
import { g, isBlank, show, debounce } from '../../utils/utils'
import styles from './index.styl'
type IProps = {
fields: IFromField[]
data: { [key: string]: any }
}
const formComponents = {
[FieldType.SELECT]: Select,
[FieldType.TEXT]: Input,
[FieldType.DATE]: DatePicker,
[FieldType.IMAGE]: ImageForm,
[FieldType.RADIO]: Radio,
}
export default class Form extends Component<IProps> {
state = {
value: '',
scrollable: true,
modal: null,
canSubmit: false,
submiting: false,
}
constructor(props) {
super(props)
this.onChange = this.onChange.bind(this)
}
componentDidMount() {
this.checkCanSubmit = debounce(this.checkCanSubmit.bind(this))
this.submitHandler = debounce(this.submitHandler.bind(this), 50)
}
/**
* @description: 修改回调
* @param {*} key
* @param {*} value
* @param {*} callback
* @return {*}
*/
async onChange(key: string, value: any, callback?: Function) {
try {
this.props.onChange && (await this.props.onChange(key, value))
// callback && callback()
this.checkCanSubmit()
} catch (error) {
console.log(error)
}
}
/**
* @description: 是否可以提交
*/
checkCanSubmit() {
const { fields, data } = this.props
for (const item of fields) {
if (isBlank(item.rules)) continue
// 校验是否可以提交
for (const rule of item.rules) {
if (rule.required && isBlank(data[item.field])) {
return this.setState({ canSubmit: false })
}
if (rule.pattern && R.complement(R.test)(rule.pattern, data[item.field])) {
return this.setState({ canSubmit: false })
}
}
this.setState({ canSubmit: true })
}
}
/**
* modal框开关回调
* @param modalOpen 是否有modal框打开
*/
modalCallback(modal?: Component) {
this.setState({ modal })
}
/**
* @description: 提交信息
*/
async submitHandler() {
this.setState({ submiting: true })
this.props.submitHandler && (await this.props.submitHandler())
this.setState({ submiting: false })
}
render() {
const { fields = [], data = {} } = this.props
const { scrollable, modal, canSubmit, submiting } = this.state
return (
<View style={g(styles, 'container')}>
<ScrollView style={g(styles, 'form')}>
<KeyboardAvoidingView style={g(styles, 'form-inner')} behavior="padding" enabled>
{fields.map(item => {
let FormComponent = formComponents[item.type] || Select
if (item.type === FieldType.CUSTOM) {
FormComponent = item.component
}
return (
<FormComponent
key={item.field}
item={item}
value={data[item.field]}
data={data}
fields={fields}
onChange={this.onChange}
modalCallback={this.modalCallback.bind(this)}
/>
)
})}
<TouchableOpacity
style={g(styles, {
'submit-btn': true,
'submit-btn__disabled': !canSubmit || submiting,
})}
disabled={!canSubmit || submiting}
activeOpacity={0.8}
onPress={this.submitHandler}
>
{submiting ? (
<View style={g(styles, 'submit-btn__inner')}>
<ActivityIndicator style={g(styles, 'submit-btn__loading')} color="rgba(255,255,255,0.5)" />
<Text style={g(styles, 'submit-btn__text', 'submit-btn__text__disabled', 'ml10')}>提交中</Text>
</View>
) : (
<Text
style={g(styles, {
'submit-btn__text': true,
'submit-btn__text__disabled': !canSubmit,
})}
>
提交
</Text>
)}
</TouchableOpacity>
</KeyboardAvoidingView>
</ScrollView>
{/* form内层的弹出窗 */}
{modal}
</View>
)
}
}
/*
* @FilePath: /BoneHouse_Business_APP/src/components/form/input.tsx
* @Author: peii
* @Date: 2021-05-06 13:05:38
* @Vision: 1.0
* @Description: 文本输入组件
*
*/
import React, { Component } from 'react'
import { View, Text, Image, TouchableOpacity, TextInput } from 'react-native'
import { IFormField } from 'bonehouse'
import * as R from 'ramda'
import { isBlank, show, isRequired, debounce } from '../../utils/utils'
import { placehold_text_color } from '../../assets/styles/base'
import { FieldType } from '../../enums'
import { g } from '../../utils/utils'
import { Title } from './common'
import styles from './index.styl'
type IProps = {
item: IFormField
onChange: Function
}
export default class Input extends Component<IProps> {
constructor(props) {
super(props)
this.onChangeText = debounce(this.onChangeText.bind(this), 500)
}
onChangeText(text: string) {
const { item, onChange } = this.props
onChange && onChange(item.field, text)
}
render() {
const { item, value } = this.props
return (
<View style={g(styles, { 'form-item': true, 'form-item-multi': item.multiline })}>
<Title item={item} />
<TextInput
style={g(styles, {
'form-input': true,
'form-text-input': true,
'form-text-input__multi': item.multiline,
})}
defaultValue={value}
autoCapitalize="none"
placeholder={item.placeholder || '请输入'}
onChangeText={this.onChangeText}
multiline={item.multiline}
numberOfLines={4}
maxLength={140}
placeholderTextColor={placehold_text_color}
underlineColorAndroid="transparent"
/>
</View>
)
}
}
/*
* @FilePath: /BoneHouse_Hospital_APP/src/components/form/radio.tsx
* @Author: peii
* @Date: 2021-06-06 16:24:05
* @Vision: 1.0
* @Description: Radio组件
*
* @Revision:
*
*/
import React, { Component } from 'react'
import { View, Text, Image, TouchableOpacity } from 'react-native'
import { IFormField, IOption } from 'bonehouse'
import * as R from 'ramda'
import { isBlank, show, isNotBlank, g } from '../../utils/utils'
import { FieldType } from '../../enums'
import { Title } from './common'
import styles from './index.styl'
type IProps = {
item: IFormField
data: any
value: any
}
export default class RadioButton extends Component<IProps> {
shouldComponentUpdate(nextProps: IProps): boolean {
if (nextProps.value !== this.props.value) {
return true
}
return false
}
render() {
const { item, value, onChange } = this.props
return (
<View style={g(styles, 'form-item')}>
<Title item={item} />
<View style={g(styles, 'form-radio')}>
{item.options &&
item.options.map(option => {
return (
<TouchableOpacity
style={g(styles, 'form-radio__item')}
key={option.value}
activeOpacity={0.8}
onPress={() => {
if (value === option.value) return
onChange(item.field, option.value)
}}
>
<View style={g(styles, 'form-radio__item-box')}>
{value === option.value && (
<Image
style={g(styles, 'form-radio__item-image')}
source={require('../../assets/images/ic_checked_blue.png')}
></Image>
)}
</View>
<Text style={g(styles, 'form-radio__item-text')}>{option.label}</Text>
</TouchableOpacity>
)
})}
</View>
</View>
)
}
}
@import '../../assets/styles/base.styl'
@import '../../assets/styles/variable.styl'
.option-text
width 100%
text-align center
color third_text_color
font-size second_text_size
.select
width 100%
height 100%
padding 30px 0 40px
&-bd
width 100%
height 100%
&-option
height 35px
justify-content center
&__text
@extend .option-text
&-active
@extend .option-text
color first_text_color
.loading
flex-direction row
height 100%
justify-content center
align-items center
&-text
font-size second_text_size
color second_text_color
margin-left 5px
.modal-header
@extend .row
width 414px
height 32px
justify-content space-between
align-items center
\ No newline at end of file
/*
* @FilePath: /BoneHouse_Hospital_APP/src/components/form/select-modal.tsx
* @Author: peii
* @Date: 2021-04-27 21:53:02
* @Vision: 1.0
* @Description: 选择组件的弹出框
*
* @Revision:
* 1.1 添加多选
*/
// @ts-nocheck
import React, { useEffect, useRef, useState, createRef } from 'react'
import { View, Text, TouchableOpacity, ActivityIndicator, FlatList } from 'react-native'
import { Provider, Modal } from '@ant-design/react-native'
import { IOption } from 'bonehouse'
import * as R from 'ramda'
import { isBlank } from '../../utils/utils'
import { BottomModal } from '../modals/base/bottom'
import { FieldType } from '../../enums'
import { g } from '../../utils/utils'
import styles from './select-modal.styl'
type IModalProps = {
data: IOption[]
value: string | number
mask?: boolean
loading: boolean
title?: string
visible: boolean
onChange?: Function
onClose: Function
}
let scrollRef = null
/**
* @description: 选择器弹窗
* @param {IModalProps} props
* @return {*}
*/
export function SelectModal(props: IModalProps) {
const { data = [], value, mask, onChange, visible, title, onClose, loading, headerHeight } = props
const [contentHeight, setContentHeight] = useState(300)
const [action, setAction] = useState(0)
useEffect(() => {
setContentHeight(35 * data.length + 70)
const idx = R.findIndex(R.propEq('value', value))(data)
if (idx > 1) {
scrollRef && scrollRef.scrollToIndex({ animated: true, index: idx })
}
}, [data.length])
const Item = ({ item }) => {
return (
<TouchableOpacity
activeOpacity={0.8}
style={g(styles, 'select-option')}
onPress={() => {
onChange && onChange(item.value)
setAction(action + 1)
}}
>
<Text
numberOfLines={1}
style={g(styles, {
'select-option__text': true,
'select-option__text-active': !!value && R.includes(item.value, value),
})}
>
{item.label}
</Text>
</TouchableOpacity>
)
}
return (
<BottomModal
contentHeight={contentHeight}
visible={visible}
onClose={onClose}
action={action}
headerHeight={headerHeight}
>
{/* <View style={g(styles, 'modal-header')}>
<TouchableOpacity style={g(styles, 'modal-header__btn')}>
<Text style={g(styles, 'modal-header__btn-text')}>取消</Text>
</TouchableOpacity>
<TouchableOpacity style={g(styles, 'modal-header__btn')}>
<Text style={g(styles, 'modal-header__btn-text')}>确定</Text>
</TouchableOpacity>
</View> */}
{!!loading ? (
<View style={g(styles, 'loading')}>
<ActivityIndicator size="small" />
<Text style={g(styles, 'loading-text')}>加载中</Text>
</View>
) : (
<View style={g(styles, 'select')}>
<FlatList
style={g(styles, 'select-bd')}
renderItem={Item}
data={data}
keyExtractor={item => item.value}
ref={ref => (scrollRef = ref)}
getItemLayout={(item, index) => {
return { length: item.length, offset: 35 * index, index }
}}
/>
</View>
)}
</BottomModal>
)
}
/*
* @FilePath: /BoneHouse_Hospital_APP/src/components/form/select.tsx
* @Author: peii
* @Date: 2021-04-25 23:36:10
* @Vision: 1.0
* @Description: 选择器组件
*
*/
// @ts-nocheck
import React, { Component } from 'react'
import { View, Text, Image, TouchableOpacity } from 'react-native'
import { IFormField, IOption } from 'bonehouse'
import * as R from 'ramda'
import { isBlank, show, isRequired, isNotBlank, g } from '../../utils/utils'
import { FieldType, SelectMode } from '../../enums'
import { Title } from './common'
import { SelectModal } from './select-modal'
import styles from './index.styl'
type IProps = {
item: IFormField
value: any
onChange: Function
data: any
fields: any[]
modalCallback: Function
}
/**
* @description: 获取显示字符
* @param {*} item
* @param {*} val
* @return {*}
*/
const getText = (item: IFormField, val) => {
if (!val) return null
if (item.multiline) {
let values = R.ifElse(isBlank, R.always([]), R.split(','))(val)
return R.compose(
R.join(','),
R.pluck('label'),
R.filter(R.pipe(R.prop('value'), R.includes(R.__, values))),
R.propOr([], 'options'),
)(item)
} else {
return R.compose(R.prop('label'), R.find(R.propEq('value', val)), R.propOr([], 'options'))(item)
}
}
export default class Select extends Component<IProps> {
state = {
visible: false,
loading: false,
}
constructor(props) {
super(props)
this.onPressHandler = this.onPressHandler.bind(this)
this.onChange = this.onChange.bind(this)
}
componentWillReceiveProps(nextProps, nextState) {
const { item, value } = nextProps
const { visible, loading } = this.state
// 当前只有一个选项时,赋值第一个选项作为当前选项值
if (item && item.options && item.options.length === 1 && item.options[0].value !== value) {
this.onChange(item.options[0].value)
}
// 换了options,表示依赖的项没有了,把当前设置为空
const val = getText(item, value)
if (isNotBlank(value) && isBlank(val) && R.complement(R.equals)(this.props.data, nextProps.data)) {
this.onChange(null)
}
// 因为是回调中设置的ReactElement,所以只有手动更新
// item的loading与当前组件的loading有且只有一个为true且visible为true的时候,手动更新Modal的状态
if ((item.loading || loading) && item.loading !== loading) {
this.setState({ loading: item.loading }, () => {
if (loading && visible) {
const modal = (
<SelectModal
data={item.options}
loading={item.loading}
value={value}
visible={true}
mask={true}
onChange={this.onChange}
onClose={() => {
this.setState({ visible: false }, () => {
this.props.modalCallback()
})
}}
/>
)
this.props.modalCallback(modal)
}
})
}
}
/**
* @description: 点击显示行
*/
onPressHandler() {
const { item, data, fields, value } = this.props
if (item.disabled) return
// 需要先选择依赖的字段
for (const ref of item.refrence || []) {
if (isBlank(data[ref])) {
const field = R.find(R.propEq('field', ref))(fields)
if (isNotBlank(field)) {
return show(`请先选择${field.label}`)
}
}
}
// 跳转到其他页面的选择
if (item.selectMode === SelectMode.PAGE) {
return item.customHandler && item.customHandler(item.field)
}
if (!item.loading && isBlank(item.options)) return show(`没有可选择的${item.label}`)
this.setState({ visible: true }, () => {
// 弹出窗,要放在最外层, 所以放在这里作为参数返回给父组件
const modal = (
<SelectModal
data={item.options}
loading={item.loading}
value={value}
visible={true}
mask={true}
onChange={this.onChange}
onClose={() => {
this.setState({ visible: false }, () => {
this.props.modalCallback()
})
}}
/>
)
this.props.modalCallback(modal)
})
}
/**
* @description: 点击弹出选中值
*/
onChange(val: any): void {
const { item, value } = this.props
// 多选
if (item.multiline) {
let values = R.ifElse(isBlank, R.always([]), R.split(','))(value)
if (R.includes(val, values)) {
values = R.compose(R.remove(R.__, 1, values), R.findIndex(R.equals(val)))(values)
} else {
values = R.append(val, values)
}
this.props && this.props.onChange(item.field, R.join(',', values))
}
// 单选
else {
if (val === value) return
this.props && this.props.onChange(item.field, val, item.callback)
}
}
render() {
const { item, value } = this.props
const text = getText(item, value)
return (
<>
<TouchableOpacity
style={g(styles, 'form-item')}
activeOpacity={item.disabled ? 1 : 0.8}
onPress={this.onPressHandler}
>
<Title item={item} />
<View style={g(styles, 'form-input')}>
{/* 值 */}
{isBlank(value) ? (
<Text style={g(styles, 'form-input__placeholder')}>{item.placeholder || '请选择'}</Text>
) : (
<Text numberOfLines={2} style={g(styles, 'form-input__text')}>
{text}
</Text>
)}
{/* 箭头 */}
{item.arrow !== false && (
<Image source={require('../../assets/images/arr_rig.png')} style={g(styles, 'form-input__arrow')} />
)}
</View>
</TouchableOpacity>
</>
)
}
}
/*
* @FilePath: /BoneHouse_Business_APP/src/components/form/textarea.tsx
* @Author: peii
* @Date: 2021-05-06 13:05:38
* @Vision: 1.0
* @Description: 多行文本输入组件
*
*/
import React, { Component } from 'react'
import { View, Text, Image, TouchableOpacity, } from 'react-native'
import { IFormField } from 'bonehouse'
import * as R from 'ramda'
import { isBlank, show, isRequired, debounce } from '../../utils/utils'
import { FieldType } from '../../enums'
import { g } from '../../utils/utils'
import { SelectModal } from './select-modal'
import styles from './index.styl'
type IProps = {
item: IFormField
onChange: Function
}
export default class Input extends Component<IProps> {
constructor(props) {
super(props)
this.onChangeText = debounce(this.onChangeText.bind(this), 500)
}
onChangeText(text: string) {
const { item, onChange } = this.props
onChange && onChange(item.field, text)
}
render() {
const { item, value } = this.props
const required = isRequired(item)
return (
<View style={g(styles, 'form-item')}>
<Text style={g(styles, 'form-label')}>
{!!required && <Text style={g(styles, 'red', 'pr5')}>*</Text>}
<Text>{item.label}</Text>
</Text>
<TextInput
style={g(styles, 'form-input', 'form-text-input')}
autoCapitalize="none"
placeholder={item.placeholder || '请输入'}
onChangeText={this.onChangeText}
/>
</View>
)
}
}
@import '../../assets/styles/base.styl'
@import '../../assets/styles/variable.styl'
.header
background primary_color
&-bar
height header_height
padding 0 20px
@extend .row
@extend .center
&-back
@extend .row
@extend .center
@extend .middle
height header_height
&__img
width 20px
height @width
margin-top 1px
&__text
color title_text_color
font-size first_text_size
font-family font_family_regular
&-title
flex 1
color title_text_color
font-size first_text_size
font-family font_family_regular
text-align center
&-right
width 60px
/*
* @FilePath: /BoneHouse_Hospital_APP/src/components/header/header.tsx
* @Author: peii
* @Date: 2021-06-06 13:28:41
* @LastEditTime: 2021-10-09 11:38:11
* @LastEditors: peii
* @Vision: 1.0
* @Description:
*/
// @ts-nocheck
import React, { useState, useEffect } from 'react'
import { View, StatusBar, Platform, Text, Image, TouchableOpacity } from 'react-native'
import { g, isIphoneX } from '../../utils/utils'
import { primary_color } from '../../assets/styles/base'
import styles from './header.styl'
// import container from '../../inversify'
// import { TYPES } from '../../inversify/types'
// const store = container.get(TYPES.SysStore)
function header({ title, backgroundColor = primary_color, back = true, backCallback = () => {}, children }) {
const [statusHeight] = useState(Platform.OS === 'android' ? 0 : isIphoneX() ? 44 : 20)
// useEffect(() => {
// const height = Platform.OS === 'android' ? 0 : isIphoneX() ? 44 : 20
// setStatusHeight(height)
// store.setHeaderHeight(height + 58)
// }, [])
return (
<View style={g(styles, 'header')}>
{/* 状态栏 */}
<View style={{ backgroundColor, height: statusHeight }}>
<StatusBar barStyle="dark-content" backgroundColor={backgroundColor} />
</View>
{/* 标题栏 */}
<View style={g(styles, 'header-bar')}>
{/* 返回按钮 */}
{!!back && (
<TouchableOpacity
style={g(styles, 'header-back')}
activeOpacity={0.6}
onPress={() => {
backCallback()
}}
>
<Image style={g(styles, 'header-back__img')} source={require('../../assets/images/back.png')} />
<Text style={g(styles, 'header-back__text')}>返回</Text>
</TouchableOpacity>
)}
<Text style={g(styles, 'header-title')}>{title}</Text>
{/* 右边 */}
{!!back && <View style={g(styles, 'header-right')}>{children}</View>}
</View>
</View>
)
}
export default header
@import '../../assets/styles/base.styl'
@import '../../assets/styles/variable.styl'
.loading
&-container
flex 1
@extend .row
@extend .middle
@extend .center
background-color home_background_color
&-text
font-size second_text_size
padding-left 8px
/*
* @FilePath: /BoneHouse_Business_APP/src/components/loading/index.tsx
* @Author: peii
* @Date: 2021-05-30 17:04:50
* @Vision: 1.0
* @Description: 加载
*
* @Revision:
*
*/
import React, { Component } from 'react'
import { View, Text, ActivityIndicator } from 'react-native'
import { second_text_color } from '../../assets/styles/base'
import { g } from '../../utils/utils'
import styles from './index.styl'
export default ({
text = '加载中',
color = second_text_color,
textColor = second_text_color,
style,
}) => {
return (
<View style={[g(styles, 'loading-container'), style]}>
<ActivityIndicator style={g(styles, 'loading-icon')} color={color} />
<Text style={[g(styles, 'loading-text'), { color: textColor }]}>{text}</Text>
</View>
)
}
import React, { Component } from 'react'
import { Modal, Provider } from '@ant-design/react-native'
import styles from './base.styl'
export type IProps = {
visible: boolean
title: string
maskClosable: boolean
updateVisible: Function
footerButtons?: any[]
}
export default class BModal extends Component<IProps> {
constructor(props) {
super(props)
}
onShow(visible = true) {
this.props.updateVisible(visible)
}
onClose(visible = false) {
this.props.updateVisible(visible)
}
render() {
let { title, visible, footerButtons, maskClosable = false } = this.props
if (!visible) return <></>
return (
<Provider>
<Modal
title={title}
transparent={true}
onClose={() => {
this.onClose()
}}
maskClosable={maskClosable}
visible={visible}
footer={footerButtons}
style={styles.base}
>
{this.props.children}
</Modal>
</Provider>
)
}
}
@import '../../../assets/styles/base.styl'
@import '../../../assets/styles/variable.styl'
.modal
position absolute
left 0
top 0
z-index 99
&-mask
@extend .modal
width 100%
height 100%
background-color rgba(0, 0, 0, 0.5)
z-index 99
&-content
position absolute
width 100%
max-height 350px
min-height: 100px
background-color foundation_color
bottom 0
border-top-left-radius 5px
border-top-right-radius 5px
z-index 999
&__date
max-height 400px
&-hd
height 50px
padding 15px 20px
&__btns
flex-direction row
justify-content space-between
&-btn
color btn_sub_color
font-size second_text_size
&-bd
height 100%
/*
* @FilePath: /BoneHouse_Hospital_APP/src/components/modals/base/bottom.tsx
* @Author: peii
* @Date: 2021-04-27 21:53:02
* @Vision: 1.0
* @Description: 在下方的基础弹出框
*
* @Revision:
*
*/
import React, { useEffect, useRef, useState, createRef } from 'react'
import { View, Text, TouchableOpacity, ScrollView, Animated, Platform } from 'react-native'
import { Provider, Modal } from '@ant-design/react-native'
import { IOption } from 'bonehouse'
import * as R from 'ramda'
import Resolution from '../../../components/common/Resolution'
import { FieldType } from '../../../enums'
import { g, isBlank, isIphoneX } from '../../../utils/utils'
// import container from '../../../inversify'
// import { TYPES } from '../../../inversify/types'
import styles from './bottom.styl'
// const store = container.get(TYPES.SysStore)
type IModalProps = {
mask?: boolean
title?: string
visible: boolean
contentHeight: number
onClose: Function
action: number
headerHeight: number
}
/**
* @description: 动画函数
* @param {*} bottomAnim
* @param {*} bottom
* @param {*} opacityAnim
* @param {*} opacity
* @param {*} cb
* @return {*}
*/
export function animated(bottomAnim, bottom, opacityAnim, opacity, cb) {
Animated.parallel([
Animated.timing(bottomAnim, {
toValue: bottom,
duration: 150,
}),
Animated.timing(opacityAnim, {
toValue: opacity,
duration: 150,
}),
]).start(() => {
cb && cb()
})
}
let scrollRef = null
/**
* @description: 选择器弹窗
* @param {IModalProps} props
* @return {*}
*/
export function BottomModal(props: IModalProps) {
const {
onChange,
visible,
title,
onClose,
action,
headerHeight,
mask = true,
contentHeight = 300,
} = props
const { width, height } = Resolution.get()
const statusHeight = Platform.OS === 'android' ? 0 : isIphoneX() ? 44 : 20
const hasNavHeight = isBlank(headerHeight) ? statusHeight + 58 : headerHeight
const [modalHeight, setModalHeight] = useState(height - hasNavHeight)
const bottom = useRef(new Animated.Value(-contentHeight)).current
const opacity = useRef(new Animated.Value(0)).current
useEffect(() => {
if (visible) {
animated(bottom, 0, opacity, 1)
}
}, [visible])
useEffect(() => {
if (action) {
animated(bottom, -contentHeight, opacity, 0, onClose)
}
}, [action])
if (!visible) return <></>
return (
<Animated.View style={[g(styles, 'modal'), { width, height: modalHeight, opacity: opacity }]}>
{!!mask && (
<TouchableOpacity
style={g(styles, 'modal-mask')}
activeOpacity={1}
onPress={() => {
animated(bottom, -contentHeight, opacity, 0, onClose)
}}
></TouchableOpacity>
)}
<Animated.View style={[g(styles, 'modal-content'), { bottom, height: contentHeight }]}>
{!!title && (
<View style={g(styles, 'modal-hd')}>
<Text style={g(styles, 'modal-header__text')}>{title}</Text>
</View>
)}
<View style={g(styles, 'modal-bd')}>{props.children}</View>
</Animated.View>
</Animated.View>
)
}
@import '../../../assets/styles/base.styl'
@import '../../../assets/styles/variable.styl'
.modal
position absolute
left 0
top 0
z-index 99
&-mask
@extend .modal
bottom 0
width 100%
background-color rgba(0, 0, 0, 0.5)
z-index 99
&-content
position absolute
width 100%
max-height 350px
min-height 100px
background-color foundation_color
bottom 0
border-top-left-radius 5px
border-top-right-radius 5px
z-index 999
&__date
max-height 400px
&-hd
height 50px
padding 15px 20px
&__btns
flex-direction row
justify-content space-between
&-btn
color btn_sub_color
font-size second_text_size
&-bd
height 100%
/*
* @FilePath: /BoneHouse_Hospital_APP/src/components/modals/base/top.tsx
* @Author: peii
* @Date: 2021-04-27 21:53:02
* @Vision: 1.0
* @Description: 在上方的基础弹出框
*
* @Revision:
*
*/
import React, { useEffect, useRef, useState, createRef } from 'react'
import { View, Text, TouchableOpacity, ScrollView, Animated, Platform } from 'react-native'
import { Provider, Modal } from '@ant-design/react-native'
import { IOption } from 'bonehouse'
import * as R from 'ramda'
import Resolution from '../../../components/common/Resolution'
import { FieldType } from '../../../enums'
import { g, isBlank, isIphoneX } from '../../../utils/utils'
// import container from '../../../inversify'
// import { TYPES } from '../../../inversify/types'
import styles from './top.styl'
// const store = container.get(TYPES.SysStore)
type IModalProps = {
mask?: boolean
title?: string
visible: boolean
contentHeight: number
onClose: Function
action: number
headerHeight: number
}
/**
* @description: 动画函数
* @param {*} topAnim
* @param {*} top
* @param {*} opacityAnim
* @param {*} opacity
* @param {*} cb
* @return {*}
*/
export function animated(topAnim, top, opacityAnim, opacity, cb) {
Animated.parallel([
Animated.timing(topAnim, {
toValue: top,
duration: 150,
}),
Animated.timing(opacityAnim, {
toValue: opacity,
duration: 150,
}),
]).start(() => {
cb && cb()
})
}
let scrollRef = null
/**
* @description: 选择器弹窗
* @param {IModalProps} props
* @return {*}
*/
export function TopModal(props: IModalProps) {
const {
onChange,
visible,
title,
onClose,
action,
headerHeight,
mask = true,
contentHeight = 400,
initTop = 0,
} = props
const { width, height } = Resolution.get()
const statusHeight = Platform.OS === 'android' ? 0 : isIphoneX() ? 44 : 20
const hasNavHeight = isBlank(headerHeight) ? statusHeight + 58 : headerHeight
const [modalHeight, setModalHeight] = useState(height - hasNavHeight)
const top = useRef(new Animated.Value(-contentHeight)).current
const opacity = useRef(new Animated.Value(0)).current
useEffect(() => {
if (visible) {
animated(top, 0, opacity, 1)
}
}, [visible])
useEffect(() => {
if (action) {
animated(top, -contentHeight, opacity, 0, onClose)
}
}, [action])
if (!visible) return <></>
return (
<Animated.View
style={[g(styles, 'modal'), { width, height: modalHeight, opacity: opacity, top: initTop }]}
>
{!!mask && (
<TouchableOpacity
style={[g(styles, 'modal-mask'), { top: contentHeight - hasNavHeight }]}
activeOpacity={1}
onPress={() => {
animated(top, -contentHeight, opacity, 0, onClose)
}}
></TouchableOpacity>
)}
<Animated.View style={[g(styles, 'modal-content'), { top: 0, height: contentHeight }]}>
{!!title && (
<View style={g(styles, 'modal-hd')}>
<Text style={g(styles, 'modal-header__text')}>{title}</Text>
</View>
)}
<View style={g(styles, 'modal-bd')}>{props.children}</View>
</Animated.View>
</Animated.View>
)
}
@import '../../../assets/styles/base.styl'
@import '../../../assets/styles/variable.styl'
.form
&-item
padding 15px 5px 15px 20px
margin 30px 10px 40px
border-radius 50px
flex-direction row
background-color rgba(239, 239, 239, 1)
&-label
width 55px
font-weight bold
&-input
flex 1
import React, { Component } from 'react'
import { View, Text, TextInput, TouchableHighlight } from 'react-native'
import { inject, observer } from 'mobx-react'
import * as R from 'ramda'
import BaseModal from '../base/base'
import { placehold_text_color } from '../../../assets/styles/base'
import { g } from '../../../utils/utils'
import styles from './host.styl'
export type IProps = {
visible: boolean
updateVisible: Function
store: {
host: string
setHost: Function
}
}
class HostModal extends Component<IProps> {
state = {
protocol: 'https',
domain: '',
}
footerBtns = [
{
text: '取消',
onPress: () => console.log('取消'),
style: g(styles, 'btn'),
},
{
text: '确定',
onPress: () => {
const { domain, protocol } = this.state
this.props.store.setHost(protocol + '://' + domain)
},
style: g(styles, 'btn'),
},
]
constructor(props) {
super(props)
this.updateVisible = this.updateVisible.bind(this)
}
componentWillReceiveProps(nextProps) {
// 每次打开弹窗的时候,设置一下当前的host
if (!this.props.visible && nextProps.visible) {
this.getDomainValue()
}
}
/**
* 打开或关闭弹窗
* @param visible
*/
updateVisible(visible: boolean) {
this.props.updateVisible && this.props.updateVisible(visible)
}
/**
* 获取域名
* @param host
*/
getDomainValue() {
const { host } = this.props.store
let domain = R.split('://', host)
this.setState({ domain: domain[1] })
}
render() {
const { visible } = this.props
const { protocol, domain } = this.state
return (
<BaseModal
title="配置域名"
visible={visible}
updateVisible={this.updateVisible}
footerButtons={this.footerBtns}
>
<View style={g(styles, 'form-item')}>
<Text style={g(styles, 'form-label')}>{protocol}://</Text>
<TextInput
autoCapitalize="none"
placeholder="请输入要请求的域名"
placeholderTextColor={placehold_text_color}
returnKeyType="done"
style={g(styles, 'form-input')}
defaultValue={domain}
clearButtonMode="while-editing"
onChangeText={text => this.setState({ domain: text })}
></TextInput>
</View>
</BaseModal>
)
}
}
export default inject('store')(observer(HostModal))
@import '../../assets/styles/base.styl'
@import '../../assets/styles/variable.styl'
iconWidth = 44px
iconWidthBig = 58px
// 字符图片
.text-image
&__icon
width iconWidth
height iconWidth
&-big
width iconWidthBig
height iconWidthBig
&__text-icon
width iconWidth
height iconWidth
borderRadius 22px
justify-content center
align-items center
borderWidth 2px
&-big
width iconWidthBig
height iconWidthBig
borderRadius 29px
&-text
font-size 14px
font-family font_family_semibold
padding 3px
text-align center
line-height 18px
&-big
font-size 18px
line-height 22px
for i in 1...50
.text-icon-{i}
borderColor hsl(i * 50, 50%, 50%)
.text-icon-{i}__text
color hsl(i * 50, 50%, 50%)
/*
* @FilePath: /BoneHouse_Hospital_APP/src/components/textimage/textimage.tsx
* @Author: peii
* @Date: 2021-08-25 10:23:52
* @LastEditTime: 2021-08-25 10:45:37
* @LastEditors: peii
* @Vision: 1.0
* @Description: 文本图片
*/
// @ts-nocheck
import React from 'react'
import { View, Text, Image } from 'react-native'
import { g, isBlank, isNotBlank } from '../../utils/utils'
import * as R from 'ramda'
import styles from './textimage.styl'
// 图片定义路径
export const IMAGE_PREFIX = '/jeecg-boot/sys/common/view/'
export function TextImage({ big, image, text = '图片', colorNumber, host = '' }: ITextImageProps) {
const numClass = isNotBlank(colorNumber) ? `text-icon-${colorNumber}` : ''
text = R.compose(R.ifElse(R.compose(R.lt(3), R.length), R.take(4), R.take(2)), R.replace(/[(-)::]/g, ''))(text)
return (
<View style="text-image">
{isBlank(image) ? (
<View
style={[g(styles, { 'text-image__text-icon': true, [numClass]: true, 'text-image__text-icon-big': big })]}
>
<Text
style={g(styles, {
'text-image__text-icon-text': true,
[`${numClass}__text`]: true,
'text-image__text-icon-text-big': big,
})}
>
{text}
</Text>
</View>
) : (
<Image
source={{ uri: host + IMAGE_PREFIX + image }}
style={[g(styles, { 'text-image__icon': true, 'text-image__icon-big': big })]}
resizeMode="contain"
/>
)}
</View>
)
}
// 业务模块
export const MOBILE_BUSINESS_MODULE = 'MOBILE_BUSINESS_MODULE'
// 历史订单
export const MOBILE_HISTORICAL_ORDER = 'MOBILE_HISTORICAL_ORDER'
// 硬件管理
export const MOBILE_HARDWARE_MANAGEMENT = 'MOBILE_HARDWARE_MANAGEMENT'
// 默认头像
export const DEFAULT_AVATAR = require('./assets/images/avatar.png')
/*
* @FilePath: /BoneHouse_Hospital_APP/src/enums/index.ts
* @Author: peii
* @Date: 2021-04-24 22:45:15
* @Vision: 1.0
* @Description:
*
* @Revision:
*
*/
export enum MsgType {
INFO,
WARN,
ERROR,
SUCCESS,
}
export enum FieldType {
TEXT = 'TEXT',
SELECT = 'SELECT',
TEXTAREA = 'TEXTAREA',
DATE = 'DATE',
CHECKBOX = 'CHECKBOX',
RADIO = 'RADIO',
IMAGE = 'IMAGE',
VOICE = 'VOICE',
CUSTOM = 'CUSTOM',
}
export enum SelectMode {
PAGE = 'PAGE',
MODAL = 'MODAL',
}
/*
* @FilePath: /BoneHouse_Hospital_APP/src/inversify/index.ts
* @Author: peii
* @Date: 2021-04-29 16:38:54
* @Vision: 1.0
* @Description: DI
*
* @Revision:
*
*/
import 'reflect-metadata'
import { Container } from 'inversify'
// import { TYPES } from './types'
// import Service from '../services/service'
// import Store from '../stores/store'
// import System from '../stores/system'
// import User from '../stores/user'
// import Organization from '../stores/organization'
// import Consume from '../stores/consume'
const container = new Container({ defaultScope: 'Singleton' })
// container.bind<Service>(TYPES.Service).to(Service)
// container.bind<Store>(TYPES.Store).to(Store)
// container.bind<System>(TYPES.SysStore).to(System)
// container.bind<User>(TYPES.UserStore).to(User)
// container.bind<Organization>(TYPES.OrgStore).to(Organization)
// container.bind<Consume>(TYPES.Consume).to(Consume)
export default container
/*
* @FilePath: /BoneHouse_Business_APP/src/inversify/types.ts
* @Author: peii
* @Date: 2021-04-29 16:38:54
* @Vision: 1.0
* @Description: DI 类型
*
* @Revision:
*
*/
export const TYPES = {
Service: Symbol.for('service'),
Store: Symbol.for('store'),
SysStore: Symbol.for('system'),
UserStore: Symbol.for('user'),
OrgStore: Symbol.for('organization'),
Consume: Symbol.for('consume'),
}
@import '../../../assets/styles/base.styl'
@import '../../../assets/styles/variable.styl'
.filter
flex 1
background-color home_background_color
width 100%
z-index 999
&-bd
// padding 0 20px
height 310px
padding-bottom 20px
z-index 999
&__inner
padding 20px
z-index 999
&-ft
@extend .row
position absolute
bottom 0
width 100%
height 48px
background-color #fff
justify-content space-between
align-items center
.form
&-item
@extend .row
align-items center
width 100%
height 40px
margin-bottom 15px
&__input
flex 1
height 100%
text-align right
background-color #fff
padding 0 10px
color second_text_color
&__radio
@extend .row
&-active
background-color #E7F1FD
&-text
color second_text_color
&-active
color #007EFF
&-item
background-color #fff
padding 10px 20px
margin-right 20px
&-label
width 120px
.btn
width 50%
align-items center
justify-content center
background-color #E7F1FD
height 100%
border-right-width 1px
border-top-width 1px
border-color #ddd
&-text
color primary_color
font-size second_text_size
font-weight bold
/*
* @FilePath: /BoneHouse_Hospital_APP/src/pages/audit/components/filter.tsx
* @Author: peii
* @Date: 2021-06-07 14:37:49
* @Vision: 1.0
* @Description: 筛选
*
*/
// @ts-nocheck
import React, { Component } from 'react'
import { View, Text, ScrollView, Platform, TextInput, TouchableOpacity } from 'react-native'
import * as R from 'ramda'
import { FieldType } from '../../../enums'
import { TopModal } from '../../../components/modals/base/top'
import { g } from '../../../utils/utils'
import styles from './filter.styl'
type IProps = {
visible: boolean
onClose: Function
}
type IState = {
action: number
}
const FormComponents = {
[FieldType.RADIO]: FormRadio,
[FieldType.TEXT]: FormInput,
}
export default class FilterModal extends Component<IProps> {
state = {
action: 0,
filterData: {
header_status: ['APPROVING'],
},
filterItems: [
{
field: 'header_status',
label: '状态',
type: FieldType.RADIO,
options: [
{
label: '待审核',
value: 'APPROVING',
},
{
label: '已审核',
value: 'APPROVED',
},
],
},
{
field: 'seller_name',
label: '医生姓名',
type: FieldType.TEXT,
},
],
}
constructor(props: IProps) {
super(props)
this.onClose = this.onClose.bind(this)
this.setData = this.setData.bind(this)
this.resetHandler = this.resetHandler.bind(this)
this.filterHandler = this.filterHandler.bind(this)
}
/**
* @description: 输入
* @param {*} key 输入项
* @param {*} value 输入值
* @return {*}
*/
setData(key: string, value: any) {
const { filterData } = this.state
filterData[key] = value
this.setState({ filterData })
}
/**
* 获取过滤信息
* @returns
*/
getData() {
return this.state.filterData
}
/**
* @description: 重置操作
* @param {*}
* @return {*}
*/
resetHandler() {
this.setState({ filterData: { header_status: ['APPROVING'] } }, () => {
this.props.filterHandler &&
this.props.filterHandler({
header_status: ['APPROVING'],
})
this.onClose()
})
}
/**
* @description: 确定
* @param {*}
* @return {*}
*/
filterHandler() {
const { filterData } = this.state
this.props.filterHandler && this.props.filterHandler(filterData)
this.onClose()
}
/**
* @description: 关闭
* @param {*}
* @return {*}
*/
onClose() {
this.props.onClose && this.props.onClose()
}
render() {
const { visible } = this.props
const { action, filterData, filterItems } = this.state
return (
<TopModal visible={visible} action={action} onClose={this.onClose} initTop={0}>
<View style={g(styles, 'filter')}>
<View style={g(styles, 'filter-bd')}>
<ScrollView style={g(styles, 'filter-bd__inner')}>
{filterItems.map(item => {
const FormComponent = FormComponents[item.type] || FormInput
return (
<View style={g(styles, 'filter-item')} key={item.field}>
<FormComponent item={item} value={filterData[item.field]} onChange={this.setData} />
</View>
)
})}
</ScrollView>
</View>
<View style={g(styles, 'filter-ft')}>
<TouchableOpacity style={g(styles, 'btn')} activeOpacity={0.8} onPress={this.resetHandler}>
<Text style={g(styles, 'btn-text')}>重置</Text>
</TouchableOpacity>
<TouchableOpacity style={g(styles, 'btn')} activeOpacity={0.8} onPress={this.filterHandler}>
<Text style={g(styles, 'btn-text')}>确定</Text>
</TouchableOpacity>
</View>
</View>
</TopModal>
)
}
}
function Title({ title }) {
return <Text style={g(styles, 'form-label')}>{title}</Text>
}
function FormInput({ item, value, onChange }) {
return (
<View style={g(styles, 'form-item')}>
<Title title={item.label} />
<TextInput
placeholder="请输入"
onChangeText={text => onChange(item.field, text)}
style={g(styles, 'form-item__input')}
defaultValue={value}
/>
</View>
)
}
/**
* @description:
* @param {*} item
* @param {*} value
* @return {*}
*/
function FormRadio({ item, value, onChange }) {
return (
<View style={g(styles, 'form-item')}>
<Title title={item.label} />
<View style={g(styles, 'form-item__radio')}>
{item.options.map(option => {
return (
<TouchableOpacity
key={option.value}
activeOpacity={0.8}
style={g(styles, {
'form-item__radio-item': true,
'form-item__radio-active': R.includes(option.value, value || []),
})}
onPress={() => {
let values = R.clone(value || [])
if (R.includes(option.value, values)) {
values = R.compose(R.remove(R.__, 1, values), R.findIndex(R.equals(option.value)))(values)
} else {
values = R.append(option.value, values)
}
onChange(item.field, values)
}}
>
<Text
style={g(styles, {
'form-item__radio-text': true,
'form-item__radio-text-active': R.includes(option.value, value || []),
})}
>
{option.label}
</Text>
</TouchableOpacity>
)
})}
</View>
</View>
)
}
@import '../../assets/styles/base.styl'
@import '../../assets/styles/variable.styl'
.container
flex 1
.body
flex 1
&-no-audit
margin-bottom 32px
&-inner
flex 1
padding 0 32px
margin 32px 0 96px
.title
@extend .row
@extend .center
justify-content space-between
&-text
font-size 22px
color #666
&-status
font-size 20px
font-weight bold
color #ff4500
&__approved
color primary_color
.info
&-body
padding-top 10px
&__text
font-size 16px
line-height 30px
&-footer
margin-top 30px
&__title
font-size 19px
color #666
&-val
@extend .row
@extend .center
&__text
font-size 19px
padding-right 10px
color #666
&__icon
width 25px
height 25px
&__content
padding-top 10px
&-text
font-size 16px
line-height 30px
.lines
margin-top 30px
flex 1
&-accordion
margin-top 20px
// height 200px
&-loading
flex-direction column
margin-top 50px
justify-content space-between
background-color transparent
&-header
align-items center
justify-content flex-end
@extend .row
&__icon
width 25px
height @width
&__text
color third_text_color
font-size second_text_size
margin-right 8px
&-item
@extend .row
align-items center
padding 3px
&-odd
background-color #ceeff2
&__idx
color first_text_color
margin-right 5px
&__info
@extend .row
flex 1
flex-wrap wrap
&-text
color first_text_color
&__num
width 30px
color third_text_color
text-align right
.footer
@extend .row
@extend .center
justify-content space-around
position absolute
bottom 22px
width 100%
height 64px
.btn
@extend .center
@extend .middle
width 120px
height 40px
background-color btn_sub_color
border-radius 4px
// shadow-color btn_sub_color
// shadow-opacity 1
elevation 2
border-width 0
&-reject
background-color #fa2213
// shadow-color #fa2213
&__loading
background-color rgba(#fa2213, 0.5)
&-submit__loading
background-color rgba(btn_sub_color, 0.5)
&-text
color #fff
font-size 16px
\ No newline at end of file
/*
* @FilePath: /BoneHouse_Hospital_APP/src/pages/audit/detail.tsx
* @Author: peii
* @Date: 2021-08-24 14:54:48
* @LastEditTime: 2021-10-21 15:06:17
* @LastEditors: peii
* @Vision: 1.0
* @Description: 订单审核详情
*/
// @ts-nocheck
import React, { Component } from 'react'
import { View, SafeAreaView, ScrollView, Text, Image, FlatList, TouchableOpacity } from 'react-native'
import { INavigation } from 'navigation'
import { connect } from 'react-redux'
import * as R from 'ramda'
import Accordion from 'react-native-collapsible/Accordion'
import Resolution from '../../components/common/Resolution'
import Loading from '../../components/loading/index'
import Header from '../../components/header/header'
import { g, isBlank, show, gender, isNotBlank } from '../../utils/utils'
import { PostRequest, GetRequest } from '../../../app/network/RequestUtils'
import { exitLoginStatus } from '../../../app/action/LoginAction'
import { getUrlParams } from '../../../app/utils/Utils'
import styles from './detail.styl'
type IProps = {
navigation: INavigation
token: string
host: string
exit: Function
}
type IState = {
loading: boolean
order: any
surgeryActiveSection: number[]
}
class AuditOrderDetail extends Component<IProps, IState> {
state = {
loading: false,
order: null,
surgeryActiveSection: [0],
linesActiveSection: [],
lines: {},
totalNum: 0,
submiting: false,
}
componentDidMount() {
const order = this.props.navigation.getParam('order')
this.setState({ order })
this.getLineData(order)
}
/**
* @description: 获取订单行表
* @param {*} order
* @return {*}
*/
async getLineData(order) {
const params = {
access_token: this.props.token,
surgery_collect_number: order.surgery_collect_number,
}
try {
this.setState({ loading: true })
const res = await GetRequest(this.props.host, getUrlParams('/surgery/collect_line/search', params))
this.setState({ loading: false })
if (res.error_code === 41006) {
return this.props.exit()
}
if (res.error_code !== 0) {
return show(res.error_msg || '请求异常,请重试')
}
let lines = R.compose(
R.values,
R.groupBy(R.prop('manufacturer_code')),
R.pathOr([], ['data', 'surgery_collect_lines']),
)(res)
const total = R.compose(R.sum, R.pluck('plan_quantity'), R.flatten)(lines)
this.setState({ lines, totalNum: total, linesActiveSection: total > 0 ? R.range(0, total) : [] })
} catch (error) {
this.setState({ loading: false })
show(error.message || '请求失败')
}
}
/**
* @description: 手术信息显隐控制
* @param {number} activeSections
* @return {*}
*/
surgerySectionChange(activeSections: number[]) {
this.setState({ surgeryActiveSection: activeSections })
}
/**
* @description: 产品信息显示隐藏控制
* @param {number} activeSections
* @return {*}
*/
linesAccordionChange(activeSections: number[]) {
this.setState({ linesActiveSection: activeSections })
}
/**
* @description: 审核(通过、拒绝)
* @param {string} processCode
* @return {*}
*/
async submitHandler(processCode: string) {
const { token, host } = this.props
const { order, submitting } = this.state
if (submitting) {
return show('正在提交中,请稍后重试')
}
const params = {
data: {
surgery_collect_number: order.collect_number,
process_code: processCode,
},
}
try {
this.setState({ submitting: true })
const res = await PostRequest(host, `/surgery/collect_order/process?access_token=${token}`, params)
this.setState({ submitting: false })
console.log(res)
if (R.isNil(res.error_code)) {
throw new Error(res.statusText)
}
if (res.error_code === 41006) {
return this.props.exit()
}
if (res.error_code !== 0) {
return show(res.error_msg)
}
const msg = R.cond([
[R.equals('APPROVE'), R.always('审核通过成功')],
[R.equals('REJECT'), R.always('拒绝单据成功')],
[R.equals('REVOKE'), R.always('借货单撤回成功')],
[R.T, R.always('审核通过成功')],
])(processCode)
show(msg)
this.props.navigation.state.params.onRefresh(true)
this.props.navigation.goBack()
} catch (error) {
this.setState({ submitting: false })
show(error.message || '请求失败,请稍后重试')
}
}
render() {
const title = this.props.navigation.getParam('title', '订单详情')
const order = this.props.navigation.getParam('order', {})
const type = this.props.navigation.getParam('type', 'AUDIT')
const { surgeryActiveSection, lines, totalNum, linesActiveSection, loading, submitting } = this.state
const sections = R.compose(
R.map(
R.applySpec({
title: lines => {
const line = R.pathOr({}, [0])(lines)
let title = line.manufacturer_name || line.manufacturer_product_code || '其他厂商'
const sum = R.compose(R.sum, R.pluck('plan_quantity'))(lines)
return title + ` [${sum}]`
},
content: R.identity,
}),
),
)(lines)
return (
<View style={g(styles, 'container')}>
<Resolution.FixWidthView>
<Header
title={title}
backCallback={() => {
this.props.navigation.goBack()
}}
/>
<View style={g(styles, { body: true })}>
<ScrollView style={g(styles, { 'body-inner': true, 'body-no-audit': order.header_status !== 'APPROVING' })}>
<View style={g(styles, 'info')}>
<Title title="订单详情">
<Text
style={g(styles, {
'title-status': true,
'title-status__approved': order.header_status === 'APPROVED',
})}
>
{order.header_status_name}
</Text>
</Title>
<View style={g(styles, 'info-body')}>
<Text style={g(styles, 'info-body__text')}>订单号:{order.surgery_collect_number}</Text>
<Text style={g(styles, 'info-body__text')}>订单类型:{order.order_type_name}</Text>
<Text style={g(styles, 'info-body__text')}>下单时间:{order.create_time}</Text>
<Text style={g(styles, 'info-body__text')}>手术时间:{order.surgery_date}</Text>
<View style={g(styles, 'info-body__remark')}>
<Text style={g(styles, 'info-body__text')}>备注信息:</Text>
<Text style={g(styles, 'info-body__text')}>{order.remark}</Text>
</View>
</View>
{/* 手术信息 */}
{order.order_type_code === 'SURGERY_ORDER' && (
<View style={g(styles, 'info-footer')}>
<Accordion
activeSections={surgeryActiveSection}
onChange={this.surgerySectionChange.bind(this)}
sections={['手术信息']}
underlayColor="transparent"
renderHeader={title => (
<Title title={title} style={g(styles, 'info-footer__title')}>
<View style={g(styles, 'info-footer__title-val')}>
<Text style={g(styles, 'info-footer__title-val__text')}>
{order.hospitalization_number}
</Text>
<Image
style={g(styles, 'info-footer__title-val__icon')}
source={
isBlank(surgeryActiveSection)
? require('../../assets/images/arr_top.png')
: require('../../assets/images/arr_bom.png')
}
></Image>
</View>
</Title>
)}
renderContent={() => (
<View style={g(styles, 'info-footer__content')}>
<Text style={g(styles, 'info-footer__content-text')}>手术规划:{order.source_number}</Text>
<Text style={g(styles, 'info-footer__content-text')}>姓名:{order.patient_name}</Text>
<Text style={g(styles, 'info-footer__content-text')}>
性别:{gender(order.patient_gender)}
</Text>
</View>
)}
></Accordion>
</View>
)}
</View>
<View style={g(styles, 'lines')}>
<Title title={`产品信息` + (totalNum > 0 ? `(${R.length(lines)}厂商|共${totalNum}件)` : '')} />
{loading && <Loading style={g(styles, 'lines-loading')} />}
{/* 行信息 */}
<View style={g(styles, 'lines-accordion')}>
{!loading && isNotBlank(lines) && (
<Accordion
sections={sections}
activeSections={linesActiveSection}
underlayColor="transparent"
onChange={this.linesAccordionChange.bind(this)}
renderHeader={(content, index, isActive, sections) => {
return (
<View style={g(styles, 'lines-header')}>
<Text style={g(styles, 'lines-header__text')}>{content.title}</Text>
<Image
style={g(styles, 'lines-header__icon')}
source={
isActive
? require('../../assets/images/arr_bom.png')
: require('../../assets/images/arr_top.png')
}
/>
</View>
)
}}
renderContent={(content, index, isActive) => <Lines lines={content.content} />}
/>
)}
</View>
</View>
</ScrollView>
{/* 审核 */}
{order.header_status === 'APPROVING' && type === 'AUDIT' && (
<View style={g(styles, 'footer')}>
<TouchableOpacity
style={g(styles, { btn: true, 'btn-reject': true, 'btn-reject__loading': submitting })}
activeOpacity={0.8}
disabled={submitting}
onPress={() => {
this.submitHandler('REJECT')
}}
>
<Text style={g(styles, 'btn-text')}>拒绝</Text>
</TouchableOpacity>
<TouchableOpacity
style={g(styles, { btn: true, 'btn-submit': true, 'btn-submit__loading': submitting })}
activeOpacity={0.8}
disabled={submitting}
onPress={() => {
this.submitHandler('APPROVE')
}}
>
<Text style={g(styles, 'btn-text')}>审核通过</Text>
</TouchableOpacity>
</View>
)}
{/* 用户自己撤销 */}
{order.header_status === 'APPROVING' && type === 'REVOKE' && (
<View style={g(styles, 'footer')}>
<TouchableOpacity
style={g(styles, { btn: true, 'btn-reject': true, 'btn-reject__loading': submitting })}
activeOpacity={0.8}
disabled={submitting}
onPress={() => {
this.submitHandler('REVOKE')
}}
>
<Text style={g(styles, 'btn-text')}>撤回订单</Text>
</TouchableOpacity>
</View>
)}
</View>
</Resolution.FixWidthView>
</View>
)
}
}
/**
* @description: 标题组件
* @param {*} param1
* @return {*}
*/
const Title = ({ title = '订单详情', children, style }) => {
return (
<View style={g(styles, 'title')}>
<Text style={[g(styles, 'title-text'), style]}>{title}</Text>
{children}
</View>
)
}
/**
* @description: 借货行厂商
* @param {*}
* @return {*}
*/
const Lines = ({ lines = [] }) => {
return (
<View style={g(styles, 'lines-inner')}>
<FlatList
data={lines}
renderItem={({ item, index }) => <LinesItem item={item} index={index + 1} />}
keyExtractor={item => item.item_code}
/>
</View>
)
}
/**
* @description: 借货行项
* @param {*} param1
* @return {*}
*/
const LinesItem = ({ item, index }) => {
return (
<View style={g(styles, { 'lines-item': true, 'lines-item-odd': index % 2 === 0 })}>
<Text style={g(styles, 'lines-item__idx')}>{index}.</Text>
<View style={g(styles, 'lines-item__info')}>
<Text style={g(styles, 'lines-item__info-text')}>{item.item_name}</Text>
{/* <Text style={g(styles, 'lines-item__info-text')}>({item.general_name})</Text> */}
<Text style={g(styles, 'lines-item__info-text')}>{item.specification}</Text>
</View>
<Text style={g(styles, 'lines-item__num')}>× {item.plan_quantity}</Text>
</View>
)
}
const mapStateToProps = state => ({
token: state.login.token,
host: state.login.global_domain_config,
})
const mapDispatchToProps = dispatch => ({
exit: () => {
dispatch(exitLoginStatus())
},
})
export default connect(mapStateToProps, mapDispatchToProps)(AuditOrderDetail)
@import '../../assets/styles/base.styl'
@import '../../assets/styles/variable.styl'
.container
flex 1
.filter
width 100%
align-items flex-end
&-icon
width 30px
height @width
margin-top 5px
.body
flex 1
.list
padding 10px 0
flex 1
.empty
padding-top 100px
.item
padding 0px 20px
&-content
@extend .row
@extend .center
border-bottom-width 1px
border-bottom-color #ddd
padding 10px 0
&-doctor
@extend .middle
@extend .center
margin-right 20px
&__text
font-size 16px
font-family font_family_semibold
font-weight bold
color #666
&-info
flex 1
&__title
font-size 18px
font-family font_family_regular
line-height 30px
color #666
font-weight bold
&__text
font-size 16px
font-family font_family_regular
&__time
font-size 14px
font-family font_family_regular
&-status
align-items flex-end
&__text
font-family font_family_regular
&__status
font-size 18px
font-weight bold
color #ff4500
&-approved
color primary_color
/*
* @FilePath: /BoneHouse_Hospital_APP/src/pages/audit/index.tsx
* @Author: peii
* @Date: 2021-08-24 14:54:28
* @LastEditTime: 2021-10-21 15:12:37
* @LastEditors: peii
* @Vision: 1.0
* @Description: 订单审核列表
*/
// @ts-nocheck
import React, { Component } from 'react'
import { View, SafeAreaView, FlatList, Text, TouchableOpacity, Image } from 'react-native'
import { INavigation } from 'navigation'
import { connect } from 'react-redux'
import * as R from 'ramda'
import dayjs from 'dayjs'
import Resolution from '../../components/common/Resolution'
import Empty from '../../components/empty/index'
import Header from '../../components/header/header'
import { g, isBlank, show } from '../../utils/utils'
import { GetRequest } from '../../../app/network/RequestUtils'
import { exitLoginStatus } from '../../../app/action/LoginAction'
import { getUrlParams } from '../../../app/utils/Utils'
import LoadingModal from '../../../app/containers/common/LodingModel'
import { TextImage } from '../../components/textimage/textimage'
import FilterModal from './components/filter'
import styles from './index.styl'
type IOperation = 'AUDIT' | 'REVOKE'
type IProps = {
navigation: INavigation
global_domain_config: string
userInfo: any
exit: Function
}
type IState = {
orders: any[]
}
class AuditOrder extends Component<IProps, IState> {
state = {
loading: false,
refreshing: false,
originData: [],
orders: [],
modalVisible: false,
}
componentDidMount() {
this.onRefresh = this.onRefresh.bind(this)
this.itemPressHandler = this.itemPressHandler.bind(this)
this.onClose = this.onClose.bind(this)
this.filterHandler = this.filterHandler.bind(this)
this.getData()
}
/**
* @description: 获取数据
* @param {*}
* @return {*}
*/
async getData(loading = true) {
const { global_domain_config, userInfo } = this.props
const type: IOperation = this.props.navigation.getParam('type', 'AUDIT')
const collect_header_status = R.ifElse(
R.equals('AUDIT'),
R.always(R.join(',', ['APPROVING', 'APPROVED'])),
R.always('APPROVING'),
)(type)
const params = {
access_token: userInfo.access_token,
org_code: userInfo.department_code,
collect_header_status,
}
if (type === 'REVOKE') {
params.seller_code = this.props.userInfo.user_name
}
try {
this.setState({ loading })
const res = await GetRequest(global_domain_config, getUrlParams('/surgery/collect_order/search', params))
console.log('res:', res)
this.setState({ loading: false })
if (res.error_code === 41006) {
return this.props.exit()
}
if (res.error_code !== 0) {
return show(res.error_msg)
}
const originData = R.pathOr([], ['data', 'surgery_collect_headers'])(res)
this.setState({ originData }, () => {
let filterData = {}
if (type === 'AUDIT') {
filterData = this.filterModal.getData()
}
this.filterHandler(filterData)
})
} catch (error) {
show(error.message || '请求失败')
}
}
/**
* @description: 下拉刷新
* @param {*}
* @return {*}
*/
async onRefresh() {
this.setState({ refreshing: true })
await this.getData(false)
this.setState({ refreshing: false })
}
/**
* @description: 行点击
* @param {*} item
* @return {*}
*/
itemPressHandler(item) {
const type = this.props.navigation.getParam('type')
this.props.navigation.navigate('AuditOrderDetail', { order: item, onRefresh: this.getData.bind(this), type })
}
onClose() {
this.setState({ modalVisible: false })
}
/**
* @description: 过滤
* @param filterData
*/
filterHandler(filterData) {
const { originData } = this.state
let data = R.clone(originData)
R.compose(
R.map(key => {
const filter = filterData[key]
if (isBlank(filter)) return
if (R.type(filter) === 'Array') {
data = R.filter(R.compose(R.includes(R.__, filter), R.prop(key)))(data)
} else if (R.type(filter) === 'String') {
const regExp = new RegExp(filter, 'g')
data = R.filter(R.compose(R.test(regExp), R.prop(key)))(data)
}
}),
R.keys,
)(filterData)
this.setState({ orders: data })
}
/**
* @description: 单项List
* @param {*} param
* @return {*}
*/
_renderItem({ item, index }) {
return (
<View style={g(styles, 'item')}>
<TouchableOpacity
style={g(styles, 'item-content')}
onPress={() => this.itemPressHandler(item)}
activeOpacity={0.8}
>
<View style={g(styles, 'item-doctor')}>
<TextImage big={true} text={item.seller_name} colorNumber={index + 1} />
<Text style={g(styles, 'item-doctor__text')}>{item.seller_name || item.patient_name}</Text>
</View>
<View style={g(styles, 'item-info')}>
<Text style={g(styles, 'item-info__title')} numberOfLines={1}>
{item.surgery_name || item.surgery_collect_number}
</Text>
<Text style={g(styles, 'item-info__text')}>{item.surgery_collect_number}</Text>
<Text style={g(styles, 'item-info__time')}>
{item.surgery_date && dayjs(item.surgery_date).format('YYYY-MM-DD')}
</Text>
</View>
<View style={g(styles, 'item-status')}>
<Text style={g(styles, 'item-status__text')}>{item.order_type_name}</Text>
<Text
style={g(styles, {
'item-status__status': true,
'item-status__status-approved': item.header_status === 'APPROVED',
})}
>
{item.header_status_name}
</Text>
</View>
</TouchableOpacity>
</View>
)
}
render() {
const title = this.props.navigation.getParam('title')
const operation: IOperation = this.props.navigation.getParam('type', 'AUDIT')
const { orders, loading, refreshing, modalVisible } = this.state
return (
<View style={g(styles, 'container')}>
<Resolution.FixWidthView>
<Header
title={title}
backCallback={() => {
this.props.navigation.goBack()
}}
>
{operation === 'AUDIT' && (
<TouchableOpacity
style={g(styles, 'filter')}
activeOpacity={0.8}
onPress={() => {
this.setState({ modalVisible: !modalVisible })
}}
>
<Image source={require('../../assets/images/filter_icon.png')} style={g(styles, 'filter-icon')} />
</TouchableOpacity>
)}
</Header>
<View style={g(styles, 'body')}>
{/* 过滤弹窗 */}
{operation === 'AUDIT' && (
<FilterModal
visible={modalVisible}
onClose={this.onClose}
filterHandler={this.filterHandler}
ref={ref => (this.filterModal = ref)}
/>
)}
{/* 列表 */}
<FlatList
data={orders}
keyExtractor={item => item.surgery_collect_number}
renderItem={this._renderItem.bind(this)}
style={g(styles, 'list')}
refreshing={refreshing}
onRefresh={this.onRefresh}
ListEmptyComponent={<Empty style={g(styles, 'empty')} />}
/>
{loading && <LoadingModal show={loading} />}
</View>
</Resolution.FixWidthView>
</View>
)
}
}
function FilterBar() {
return <View style={g(styles, 'filter')}></View>
}
const mapStateToProps = state => ({
global_domain_config: state.login.global_domain_config,
userInfo: state.login.userInfo,
})
const mapDispatchToProps = dispatch => ({
exit: () => {
dispatch(exitLoginStatus())
},
})
export default connect(mapStateToProps, mapDispatchToProps)(AuditOrder)
@import '../../../assets/styles/base.styl'
@import '../../../assets/styles/variable.styl'
.content
padding-bottom 48px
.header
height 48px
border-bottom-width 1px
border-bottom-color rgba(222, 219, 219, 1)
justify-content center
padding 0 20px
.list
padding 0 20px
.item
@extend .row
justify-content space-between
padding 7px 0
&-info
flex 1
border-bottom-width 1px
border-bottom-color rgba(234, 234, 234, 1)
padding-bottom 7px
&__title
line-height 20px
color rgba(0, 0, 0, 0.87)
font-size 14px
font-family PingFangSC-Regular
&__number
line-height 20px
color rgba(197, 198, 197, 100)
font-size 14px
font-family PingFangSC-Regular
&-action
justify-content center
padding-left 15px
&__img
width 22px
height @width
/*
* @FilePath: /BoneHouse_Business_APP/src/pages/consume/components/consumables-modal.tsx
* @Author: peii
* @Date: 2021-05-18 20:46:57
* @Vision: 1.0
* @Description: 已选择耗材弹窗
*
*/
import React, { useEffect, useRef, useState, createRef } from 'react'
import { View, Text, TouchableOpacity, FlatList, Image } from 'react-native'
import { ISurgeryCollectLine } from 'bonehouse'
import * as R from 'ramda'
import { isBlank } from '../../../utils/utils'
import { BottomModal } from '../../../components/modals/base/bottom'
import { g } from '../../../utils/utils'
import styles from './consumables-modal.styl'
type IProps = {
onChange: Function
onClose: Function
visible: boolean
data: ISurgeryCollectLine[]
}
let onChangeHandler = null
export function ConsumablesModal(props: IProps) {
const { onChange, onClose, visible, data } = props
const [contentHeight, setContentHeight] = useState(350)
const [action, setAction] = useState(0)
useEffect(() => {
onChangeHandler = onChange
}, [])
return (
<BottomModal
contentHeight={contentHeight}
visible={visible}
onClose={onClose}
action={action}
headerHeight={89}
>
<View style={g(styles, 'content')}>
<View style={g(styles, 'header')}>
<Text>耗材({data.length})</Text>
</View>
<FlatList
style={g(styles, 'list')}
data={data}
keyExtractor={item => item.serialNumber}
renderItem={Item}
/>
</View>
</BottomModal>
)
}
/**
* @description: 渲染行
* @param {*} item
* @param {*} index
* @return {*}
*/
function Item({ item, index }: { item: ISurgeryCollectLine; index: number }) {
return (
<View style={g(styles, 'item')}>
<View style={g(styles, 'item-info')}>
<Text style={g(styles, 'item-info__title')} numberOfLines={2}>
{item.itemName} {item.specification}
</Text>
<Text style={g(styles, 'item-info__number')}>序列号: {item.serialNumber}</Text>
</View>
<TouchableOpacity
style={g(styles, 'item-action')}
onPress={() => {
onChangeHandler && onChangeHandler(item)
}}
>
<Image
source={require('../../../assets/images/close_icon.png')}
style={g(styles, 'item-action__img')}
/>
</TouchableOpacity>
</View>
)
}
@import '../../../assets/styles/base.styl'
@import '../../../assets/styles/variable.styl'
.hd
&-text
color rgba(163, 163, 163, 100)
font-size second_text_size
font-family font_family_regular
margin-bottom 10px
.bd
background-color #fff
padding 0 15px 5px 15px
margin-bottom 18px
&-title
color rgba(0, 0, 0, 1)
font-size 17px
font-family font_family_regular
line-height 50px
.item
margin-bottom 10px
&-title
font-size second_text_size
color rgba(0, 0, 0, 1)
line-height 20px
&-text
color second_text_color
font-size 14px
line-height 20px
.ft
align-items center
margin-bottom 20px
&-btn
width 343px
height 48px
border-radius 9px
background-color primary_color
justify-content center
align-items center
&__text
color btn_color
font-size second_text_size
font-family font_family_semibold
/*
* @FilePath: /BoneHouse_Business_APP/src/pages/consume/components/fees.tsx
* @Author: peii
* @Date: 2021-05-20 23:05:43
* @Vision: 1.0
* @Description: 费用明细组件
*
* @Revision:
*
*/
import React, { Component } from 'react'
import { View, Text, ScrollView, TouchableOpacity, Image } from 'react-native'
import { inject, observer } from 'mobx-react'
import { IFormField, IFee } from 'bonehouse'
import * as R from 'ramda'
import { g, isBlank, isNotBlank } from '../../../utils/utils'
import container from '../../../inversify'
import { TYPES } from '../../../inversify/types'
import styles from './fees.styl'
const store = container.get(TYPES.SysStore)
type IProps = {
item: IFormField
value: IFee[]
}
const getText = (code: string) => {
const feeTypes = store.sysValueSets.SUR_FEE_TYPE
return R.compose(R.prop('valueName'), R.find(R.propEq('valueCode', code)))(feeTypes)
}
export default (props: IProps) => {
const { item, value } = props
return (
<View style={g(styles, 'fees')}>
<View style={g(styles, 'hd')}>
<Text style={g(styles, 'hd-text')}>费用明细</Text>
</View>
{isNotBlank(value) && (
<View style={g(styles, 'bd')}>
<Text style={g(styles, 'bd-title')}>费用({R.length(value)}</Text>
{value.map((val, idx) => {
return (
<View style={g(styles, 'item')} key={R.toString(val.fid)}>
<Text style={g(styles, 'item-title')}>
{idx + 1}: {getText(val.feeType)}
</Text>
<Text style={g(styles, 'item-text')}>费用金额(¥):{val.feeAmount}</Text>
</View>
)
})}
</View>
)}
<View style={g(styles, 'ft')}>
<TouchableOpacity
style={g(styles, 'ft-btn')}
activeOpacity={0.8}
onPress={() => {
item.customHandler && item.customHandler()
}}
>
<Text style={g(styles, 'ft-btn__text')}>+添加费用明细</Text>
</TouchableOpacity>
</View>
</View>
)
}
@import '../../../assets/styles/base.styl'
@import '../../../assets/styles/variable.styl'
.hd
&-text
color rgba(163, 163, 163, 100)
font-size second_text_size
font-family font_family_regular
margin-bottom 10px
.bd
background-color #fff
padding 0 15px 5px 15px
margin-bottom 18px
&-title
color rgba(0, 0, 0, 1)
font-size 17px
font-family font_family_regular
line-height 50px
.item
margin-bottom 10px
&-title
font-size second_text_size
color rgba(0, 0, 0, 1)
line-height 20px
&-text
color second_text_color
font-size 14px
line-height 20px
.ft
align-items center
margin-bottom 20px
&-btn
width 343px
height 48px
border-radius 9px
background-color primary_color
justify-content center
align-items center
&__text
color btn_color
font-size second_text_size
font-family font_family_semibold
import React, { Component } from 'react'
import { View, Text, ScrollView, TouchableOpacity, Image } from 'react-native'
import { inject, observer } from 'mobx-react'
import { IFormField, ISurgeryCollectLine } from 'bonehouse'
import * as R from 'ramda'
import { g, isBlank, isNotBlank } from '../../../utils/utils'
import styles from './selected-consumables.styl'
type IProps = {
value: ISurgeryCollectLine[]
item: IFormField
}
export default (props: IProps) => {
const { value, item } = props
return (
<View style={g(styles, 'consumeable')}>
<View style={g(styles, 'hd')}>
<Text style={g(styles, 'hd-text')}>耗材明细</Text>
</View>
{isNotBlank(value) && (
<View style={g(styles, 'bd')}>
<Text style={g(styles, 'bd-title')}>耗材({R.length(value || [])})</Text>
{value.map((val, idx) => {
return (
<View style={g(styles, 'item')} key={val.serialNumber}>
<Text style={g(styles, 'item-title')}>
{idx + 1}. {val.itemName}
</Text>
<Text style={g(styles, 'item-text')}>序列号: {val.serialNumber}</Text>
<Text style={g(styles, 'item-text')}>单价(¥): {val.salePrice}</Text>
</View>
)
})}
</View>
)}
<View style={g(styles, 'ft')}>
<TouchableOpacity
style={g(styles, 'ft-btn')}
activeOpacity={0.8}
onPress={() => {
item.customHandler && item.customHandler()
}}
>
<Text style={g(styles, 'ft-btn__text')}>+添加消耗明细</Text>
</TouchableOpacity>
</View>
</View>
)
}
@import '../../assets/styles/base.styl'
@import '../../assets/styles/variable.styl'
.container
flex 1
.search
width 100%
height 56px
background-color primary_color
padding 12px
&-inner
flex-direction row
width 100%
height 32px
background-color #fff
border-radius 6px
@extend .center
&-text
flex 1
&-scan
width 22px
height @width
margin-right 5px
margin-left 5px
.list
padding 0 20px
&-view
flex 1
// padding 20px 0
padding-top 20px
background-color home_background_color
&-item
width 100%
background-color #fff
padding 10px
margin-bottom 20px
@extend .row
@extend .center
&__info
width 100%
&__cny
@extend .row
padding-top 10px
&-text
color list_one_color
font-size 14px
font-family font_family_regular
&-input
width 200px
color second_text_color
.info-item
@extend .row
&__text
font-size third_text_size
color list_one_light_color
font-family font_family_regular
&__key
width 65px
text-align justify
&__code
font-size second_text_size
color list_one_color
font-family font_family_semibold
&__sub-text
font-size third_text_size
color list_thr_color
font-family font_family_regular
.footer
height 88px
width 100%
background-color #fff
@extend .middle
@extend .center
&-btn
@extend .row
@extend .center
width 342px
height 52px
border-radius 10px
background-color rgba(79, 79, 79, 1)
overflow hidden
&__selected
@extend .row
padding-left 20px
flex 1
&-text
font-size 18px
color btn_color
font-family font_family_medium
&__confirm
width 116px
height 100%
background-color primary_color
@extend .center
@extend .middle
.mr10
margin-right 10px
.red
color #f00
/*
* @FilePath: /BoneHouse_Business_APP/src/pages/consume/consumables.tsx
* @Author: peii
* @Date: 2021-05-11 21:21:43
* @Vision: 1.0
* @Description: 借货订单明细页面
*
* @Revision:
*
*/
import React, { Component } from 'react'
import {
View,
Text,
Image,
TextInput,
FlatList,
TouchableWithoutFeedback,
TouchableOpacity,
} from 'react-native'
import { inject, observer } from 'mobx-react'
import { IFormField, ISurgeryCollectLine } from 'bonehouse'
import * as R from 'ramda'
import dayjs from 'dayjs'
import { ConsumablesModal } from './components/consumables-modal'
import Checkbox from '../../components/common/checkbox'
import Header from '../../components/header/header'
import Loading from '../../components/loading'
import Empty from '../../components/empty'
import { g, isBlank, isNotBlank, show } from '../../utils/utils'
import styles from './consumables.styl'
type IProps = {
consumeStore: {
orderId: string
getOrderLines: Function
orderLines: ISurgeryCollectLine[]
loading: boolean
selectedLines: ISurgeryCollectLine[]
setSelectedLines: Function
}
}
type IState = {
lines: ISurgeryCollectLine[]
}
class Consumables extends Component<IProps, IState> {
state = {
lines: [],
mainColumns: [
{
label: '物料名称',
field: 'itemName',
},
{
label: '通用名称',
field: 'generalName',
},
{
label: '规格型号',
field: 'specification',
},
],
subColumns: [
{
label: '序列号',
field: 'serialNumber',
},
{
label: '生产批号',
field: 'productionBatchNumber',
},
{
label: '生产序号',
field: 'productionSerialNumber',
},
{
label: '生产日期',
field: 'productionDate',
type: 'date',
},
{
label: '过期日期',
field: 'expirationDate',
type: 'date',
},
],
modalVisible: false,
}
constructor(props: IProps) {
super(props)
this.onSelectHandler = this.onSelectHandler.bind(this)
this.onRemoveHandler = this.onRemoveHandler.bind(this)
this.onInputPriceHandler = this.onInputPriceHandler.bind(this)
this.onConfirmHandler = this.onConfirmHandler.bind(this)
}
componentDidMount() {
this.getOrderLines()
}
/**
* @description: 获取订单明细信息
* @param {*}
* @return {*}
*/
async getOrderLines() {
const { orderId } = this.props.navigation.state.params
let orderLines = this.props.consumeStore.orderLines(orderId)
if (isBlank(orderLines)) {
await this.props.consumeStore.getOrderLines(orderId)
orderLines = this.props.consumeStore.orderLines(orderId)
}
this.setState({ lines: orderLines })
}
/**
* @description: 是否被选择
* @param {ISurgeryCollectLine} item
* @return {*}
*/
isSelected(item: ISurgeryCollectLine) {
const { selectedLines } = this.props.consumeStore
return R.compose(isNotBlank, R.find(R.propEq('serialNumber', item.serialNumber)))(selectedLines)
}
/**
* @description: 选择操作
* @param {ISurgeryCollectLine} item
* @param {boolean} checked
*/
onSelectHandler(item: ISurgeryCollectLine, checked: boolean) {
let { selectedLines, setSelectedLines } = this.props.consumeStore
// 选中
if (checked) {
const storeItem = R.find(R.propEq('serialNumber', item.serialNumber))(selectedLines)
if (isNotBlank(storeItem)) return
selectedLines = R.compose(R.append(R.__, selectedLines), R.clone)(item)
setSelectedLines(selectedLines)
}
// 取消
else {
this.onRemoveHandler(item)
}
}
/**
* @description: 删除所选
* @param {ISurgeryCollectLine} item
* @return {*}
*/
onRemoveHandler(item: ISurgeryCollectLine) {
let { selectedLines, setSelectedLines } = this.props.consumeStore
const idx = R.findIndex(R.propEq('serialNumber', item.serialNumber))(selectedLines)
if (idx === -1) return
selectedLines = R.remove(idx, 1, selectedLines)
setSelectedLines(selectedLines)
}
/**
* @description: 输入单价
* @param {*} serialNumber
* @param {*} text
* @return {*}
*/
onInputPriceHandler(serialNumber: string, text: string) {
if (isNotBlank(text) && isNaN(text)) return show('请输入数字')
const { selectedLines, setSelectedLines } = this.props.consumeStore
const item = R.find(R.propEq('serialNumber', serialNumber))(selectedLines)
if (isNotBlank(item)) {
item.salePrice = Number(text)
setSelectedLines(selectedLines)
}
}
/**
* @description: 确定耗材
* @param {*}
* @return {*}
*/
onConfirmHandler() {
const { selectedLines } = this.props.consumeStore
const { lines } = this.state
for (const item of R.values(selectedLines)) {
if (isBlank(item.salePrice)) {
return show(`请输入耗材${item.itemName}的单价`)
}
}
const { state, goBack } = this.props.navigation
const { callback } = state.params
callback && callback()
goBack()
}
/**
* @description: 列表单项渲染
* @param {*} item
* @return {*}
*/
_renderItem({ item }: { item: ISurgeryCollectLine }) {
const { mainColumns, subColumns } = this.state
const checked = this.isSelected(item)
const { selectedLines } = this.props.consumeStore
const selectItem = R.find(R.propEq('serialNumber', item.serialNumber))(selectedLines)
return (
<View style={g(styles, 'list-item')}>
<Checkbox
checked={checked}
onChange={checked => {
this.onSelectHandler(item, checked)
}}
/>
<View style={g(styles, 'list-item__info')}>
<TouchableWithoutFeedback
onPress={() => {
this.onSelectHandler(item, !checked)
}}
>
<View style={g(styles, 'list-item__info-main')}>
<Text style={g(styles, 'info-item__code')}>
{item.manufacturerProductCode || '无厂家产品代码'}
</Text>
{mainColumns.map(col => {
return (
<View style={g(styles, 'info-item')} key={col.field}>
<Text style={g(styles, 'info-item__key', 'info-item__text')}>{col.label}:</Text>
<Text style={g(styles, 'info-item__text')}>
{R.propOr('无', col.field, item)}
</Text>
</View>
)
})}
{subColumns.map(col => {
return (
<View style={g(styles, 'info-item')} key={col.field}>
<Text style={g(styles, 'info-item__sub-text', 'info-item__key')}>
{col.label}:
</Text>
<Text style={g(styles, 'info-item__sub-text')}>
{col.type === 'date'
? R.compose(d => {
return (d && dayjs(d).format('YYYY-MM-DD')) || '无'
}, R.prop(col.field))(item)
: item[col.field]}
</Text>
</View>
)
})}
</View>
</TouchableWithoutFeedback>
{/* 单价 */}
{!!checked && (
<View style={g(styles, 'list-item__cny')}>
<Text style={g(styles, ['list-item__cny-text', 'red'])}>*</Text>
<Text style={g(styles, 'list-item__cny-text')}>单价(¥):</Text>
<TextInput
style={g(styles, 'list-item__cny-input')}
placeholder="请输入单价"
defaultValue={R.compose(R.toString(), R.prop('salePrice'))(selectItem)}
onChangeText={text => this.onInputPriceHandler(item.serialNumber, text)}
/>
</View>
)}
</View>
</View>
)
}
render() {
const { lines, modalVisible } = this.state
const { loading, selectedLines } = this.props.consumeStore
return (
<View style={g(styles, 'container')}>
<Header title="消耗确认 - 消耗明细" backCallback={this.onConfirmHandler} />
{/* 搜索框 */}
<View style={g(styles, 'search')}>
<View style={g(styles, 'search-inner')}>
<Image
source={require('../../assets/images/search_icon.png')}
style={g(styles, 'search-scan')}
/>
<TextInput style={g(styles, 'search-text')} placeholder="搜索关键词"></TextInput>
<Image
source={require('../../assets/images/scan_2.png')}
style={g(styles, 'search-scan')}
/>
</View>
</View>
{/* 加载中 */}
{loading ? (
<Loading />
) : (
<>
{/* 借货单行列表 */}
<View style={g(styles, 'list-view')}>
<FlatList
renderItem={this._renderItem.bind(this)}
data={lines}
keyExtractor={(item, index) => item.itemCode + index}
style={g(styles, 'list')}
ListEmptyComponent={() => {
return <Empty />
}}
/>
</View>
{/* 下方按钮 */}
<View
style={[
g(styles, 'footer'),
{ shadowColor: '#ccc', shadowOffset: { height: -6 }, shadowOpacity: 0.3 },
]}
>
<View style={g(styles, 'footer-btn')}>
<TouchableOpacity
style={g(styles, 'footer-btn__selected')}
activeOpacity={0.8}
onPress={() => {
this.setState({ modalVisible: true })
}}
>
<Text style={g(styles, 'footer-btn__selected-text', 'mr10')}>已选:</Text>
<Text style={g(styles, 'footer-btn__selected-text')}>
{R.length(selectedLines)}
</Text>
</TouchableOpacity>
<TouchableOpacity
style={g(styles, 'footer-btn__confirm')}
activeOpacity={0.8}
onPress={this.onConfirmHandler}
>
<Text style={g(styles, 'footer-btn__selected-text')}>确定耗材</Text>
</TouchableOpacity>
</View>
</View>
{/* 已选择耗材弹窗 */}
<ConsumablesModal
visible={modalVisible}
onClose={() => {
this.setState({ modalVisible: false })
}}
data={selectedLines}
onChange={this.onRemoveHandler}
/>
</>
)}
</View>
)
}
}
export default inject('consumeStore')(observer(Consumables))
@import '../../assets/styles/base.styl'
@import '../../assets/styles/variable.styl'
.container
flex 1
/*
* @FilePath: /BoneHouse_Business_APP/src/pages/consume/consume.tsx
* @Author: peii
* @Date: 2021-04-25 18:24:09
* @Vision: 1.0
* @Description: 消耗确认页面
*
* @Revision:
*
*/
import React, { Component } from 'react'
import { View, Text, ScrollView } from 'react-native'
import { inject, observer } from 'mobx-react'
import { toJS } from 'mobx'
import { IOrganization, ISurgeryCollectHeader, IFee } from 'bonehouse'
import * as R from 'ramda'
import Form from '../../components/form'
import { FieldType } from '../../enums'
import Header from '../../components/header/header'
import { g, getFormItem, isBlank, isNotBlank, show } from '../../utils/utils'
import Consumables from './components/selected-consumables'
import Fees from './components/fees'
import styles from './consume.styl'
type IProps = {
store: {}
userStore: {
userName: string
personName: string
}
sysStore: {
sysProfiles: {
OBS_MOBILE_CONSU_DEPARTMENT_DISPLAY: string
OBS_MOBILE_CONSU_DOCTOR_DISPLAY: string
OBS_MOBILE_CONSU_FOLLOW_DISPLAY: string
}
}
orgStore: {
organizations: IOrganization[]
orgs: Function
getCustomers: Function
customers: Function
getDepartmentsBySellerAndOrg: Function
departments: Function
followers: Function
}
consumeStore: {
orders: ISurgeryCollectHeader[]
selectedLines: ISurgeryCollectLine[]
feeLines: IFee[]
getOrders: Function
orderFollower: Function
orderDoctor: Function
getOrderLines: Function
setSelectedLines: Function
resetOrderLines: Function
submit: Function
}
}
class Consume extends Component<IProps> {
constructor(props) {
super(props)
this.setData = this.setData.bind(this)
this.submitHandler = this.submitHandler.bind(this)
}
state = {
data: {
sellerCode: this.props.userStore.userName,
},
formItems: [
{
field: 'sellerCode',
label: '销售员',
type: FieldType.SELECT,
options: [
{
label: this.props.userStore.personName,
value: this.props.userStore.userName,
},
],
placeholder: '请选择',
rules: [{ required: true, message: '请选择销售员' }],
disabled: true,
},
{
field: 'orgCode',
label: '组织',
type: FieldType.SELECT,
options: this.props.orgStore.orgs(),
placeholder: '请选择',
rules: [{ required: true, message: '请选择组织' }],
callback: this.setOrgCallback.bind(this),
},
{
field: 'customerCode',
label: '客户',
type: FieldType.SELECT,
options: [],
placeholder: '请选择',
rules: [{ required: true, message: '请选择客户' }],
refrence: ['orgCode'],
callback: this.setCustomerCallback.bind(this),
},
{
field: 'surgeryCollectNumber',
label: '订单信息',
type: FieldType.SELECT,
options: [],
loading: false,
placeholder: '请选择',
rules: [{ required: true, message: '请选择订单' }],
refrence: ['orgCode', 'customerCode'],
callback: this.setSurgeryCollectNumberCallback.bind(this),
},
{
field: 'consumeDate',
label: '消耗时间',
type: FieldType.DATE,
dateMode: 'datetime',
options: [],
placeholder: '请选择',
rules: [{ required: true, message: '请选择消耗时间' }],
},
{
field: 'patientName',
label: '患者姓名',
type: FieldType.TEXT,
placeholder: '请输入患者姓名',
rules: [{ required: true, message: '请输入患者姓名' }],
},
{
field: 'patientGender',
label: '性别',
type: FieldType.SELECT,
options: [
{
label: '男',
value: '男',
},
{
label: '女',
value: '女',
},
],
placeholder: '请选择',
rules: [{ required: true, message: '请选择性别' }],
},
{
field: 'patientAge',
label: '年龄',
type: FieldType.TEXT,
placeholder: '请输入年龄',
rules: [
{ required: true, message: '请输入年龄' },
{ pattern: /\d{1,3}/, message: '请输入正确的年龄' },
],
},
{
field: 'patientBed',
label: '床位',
type: FieldType.TEXT,
placeholder: '请输入床位',
rules: [{ required: true, message: '请输入床位' }],
},
{
field: 'patientId',
label: '病历号',
type: FieldType.TEXT,
placeholder: '请输入病历号',
rules: [{ required: true, message: '请输入病历' }],
},
{
field: 'remark',
label: '备注',
type: FieldType.TEXT,
placeholder: '请输入备注',
multiline: true,
rules: [],
},
{
field: 'lines',
label: '耗材明细',
type: FieldType.CUSTOM, // 自定义类型
component: Consumables, // ReactElement
customHandler: this.orderBeforeHandler.bind(this, 'lines'),
rules: [{ required: true, message: '请选择耗材' }],
refrence: ['orgCode', 'surgeryCollectNumber'],
},
{
field: 'feeLines',
label: '费用明细',
type: FieldType.CUSTOM,
component: Fees,
customHandler: this.feeBeforeHandler.bind(this),
},
{
field: 'imgUrl',
label: '添加图片',
type: FieldType.IMAGE,
},
],
}
componentDidMount() {
this.setOptionsFormItems()
}
componentWillUnmount() {
this.props.consumeStore.resetOrderLines()
this.props.consumeStore.setSelectedLines([])
console.log('Consume page will unmount')
}
/**
* @description: 设置配置性的表单字段
* @param {*}
* @return {*}
*/
setOptionsFormItems() {
const { sysProfiles } = this.props.sysStore
let { formItems } = this.state
// 部门(00)第一位显示、第二位必需
if (R.pathEq(['OBS_MOBILE_CONSU_DEPARTMENT_DISPLAY', 0], '1', sysProfiles)) {
formItems = R.insert(
2,
{
field: 'departmentCode',
label: '部门',
type: FieldType.SELECT,
placeholder: '请选择',
options: [],
rules: [
{
required: R.pathEq(['OBS_MOBILE_CONSU_DEPARTMENT_DISPLAY', 1], '1', sysProfiles),
message: '请选择客户',
},
],
refrence: ['orgCode'],
},
formItems,
)
}
// 跟台(00)第一位显示、第二位必需
if (R.pathEq(['OBS_MOBILE_CONSU_FOLLOW_DISPLAY', 0], '1', sysProfiles)) {
const idx = R.findIndex(R.propEq('field', 'surgeryCollectNumber'))(formItems)
formItems = R.insert(
idx + 1,
{
field: 'surgeryFollowerCode',
label: '跟台员',
type: FieldType.SELECT,
placeholder: '请选择',
options: [],
rules: [
{
required: R.pathEq(['OBS_MOBILE_CONSU_FOLLOW_DISPLAY', 1], '1', sysProfiles),
message: '请选择跟台员',
},
],
refrence: ['orgCode', 'customerCode', 'surgeryCollectNumber'],
},
formItems,
)
}
// 医生(00)第一位显示、第二位必需
if (R.pathEq(['OBS_MOBILE_CONSU_DOCTOR_DISPLAY', 0], '1', sysProfiles)) {
const idx = R.findIndex(R.propEq('field', 'consumeDate'))(formItems)
formItems = R.insert(
idx + 1,
{
field: 'doctorName',
label: '医生',
type: FieldType.TEXT,
placeholder: '请输入医生姓名',
options: [],
rules: [
{
required: R.pathEq(['OBS_MOBILE_CONSU_DOCTOR_DISPLAY', 1], '1', sysProfiles),
message: '请输入医生姓名',
},
],
},
formItems,
)
}
this.setState({ formItems })
}
/**
* @description: 设置修改值
* @param {*} key
* @param {*} value
* @return {*}
*/
setData(key: string, value: any) {
return new Promise<any>((resolve, reject) => {
const { data, formItems } = this.state
data[key] = value
this.setState({ data }, () => {
const item = getFormItem(formItems, key)
item && item.callback && item.callback()
resolve()
})
})
}
/**
* @description: 选择完组织
* @param {*}
* @return {*}
*/
setOrgCallback() {
const { OBS_MOBILE_CONSU_DEPARTMENT_DISPLAY } = this.props.sysStore.sysProfiles
// 显示了部门
if (R.pathEq([0], '1', OBS_MOBILE_CONSU_DEPARTMENT_DISPLAY)) {
// 获取部门
this.getDepartments.call(this)
}
// 获取客户列表
this.getCustomers.call(this)
}
/**
* @description: 获取部门
* @param {*}
* @return {*}
*/
async getDepartments() {
const { data, formItems } = this.state
const { orgCode, sellerCode } = data
let departments = this.props.orgStore.departments(sellerCode, orgCode)
const item = getFormItem(formItems, 'departmentCode')
if (isBlank(departments)) {
item.loading = true
await this.props.orgStore.getDepartmentsBySellerAndOrg(sellerCode, orgCode)
item.loading = false
departments = this.props.orgStore.departments(sellerCode, orgCode)
}
item.options = departments
this.setState({ formItems })
}
/**
* 获取客户列表
*/
async getCustomers() {
const { data, formItems } = this.state
const { orgCode, sellerCode } = data
let customers = this.props.orgStore.customers(sellerCode, orgCode)
const item = getFormItem(formItems, 'customerCode')
if (isBlank(customers)) {
item.loading = true
await this.props.orgStore.getCustomers(sellerCode, orgCode)
item.loading = false
customers = this.props.orgStore.customers(sellerCode, orgCode)
}
item.options = customers
this.setState({ formItems })
}
/**
* @description: 客户选择完回调
* @param {*}
* @return {*}
*/
async setCustomerCallback() {
const { data, formItems } = this.state
let orders = this.props.consumeStore.orders(data.sellerCode, data.orgCode, data.customerCode)
const item = getFormItem(formItems, 'surgeryCollectNumber')
if (isBlank(orders)) {
item.loading = true
await this.props.consumeStore.getOrders({
sellerCode: data.sellerCode,
orgCode: data.orgCode,
customerCode: data.customerCode,
collectHeaderStatus: 'RETURNED,COLLECTED',
})
item.loading = false
orders = this.props.consumeStore.orders(data.sellerCode, data.orgCode, data.customerCode)
}
item.options = orders
this.setState({ formItems })
}
/**
* @description: 订单信息选择完回调
* @param {*}
* @return {*}
*/
async setSurgeryCollectNumberCallback() {
const { data, formItems } = this.state
let followers = this.props.orgStore.followers(
data.sellerCode,
data.orgCode,
data.departmentCode,
)
const orderFollower = this.props.consumeStore.orderFollower(
data.sellerCode,
data.orgCode,
data.customerCode,
data.surgeryCollectNumber,
)
const doctor = this.props.consumeStore.orderDoctor(
data.sellerCode,
data.orgCode,
data.customerCode,
data.surgeryCollectNumber,
)
data.doctorName = doctor
if (isNotBlank(orderFollower)) {
data.surgeryFollowerCode = orderFollower.value
const follower = R.find(R.propEq('value', orderFollower.value))(followers)
if (isBlank(follower)) {
followers = R.append(orderFollower, followers)
}
} else {
data.surgeryFollowerCode = null
}
const item = getFormItem(formItems, 'surgeryFollowerCode')
if (isNotBlank(item)) {
item.options = followers
this.setState({ formItems }, () => {
this.setState({ data })
})
}
this.props.consumeStore.getOrderLines(data.surgeryCollectNumber)
this.props.consumeStore.setSelectedLines([])
}
/**
* @description: 依赖项检查
* @param {*} itemName
* @return {*}
*/
refrenceCheck(itemName: string) {
const { data, formItems } = this.state
const item = R.find(R.propEq('field', itemName))(formItems)
if (isBlank(item)) {
return true
}
// 需要先选择依赖的字段
for (const ref of item.refrence || []) {
if (isBlank(data[ref])) {
const field = R.find(R.propEq('field', ref))(formItems)
if (isNotBlank(field)) {
show(`请先选择${field.label}`)
return false
}
}
}
return true
}
/**
* @description: 添加消耗明细跳转前处理
* @param {*}
* @return {*}
*/
orderBeforeHandler(itemName: string) {
if (!this.refrenceCheck(itemName)) return
const { data } = this.state
this.props.navigation.navigate('Consumables', {
orderId: data.surgeryCollectNumber,
// 添加消耗明细后处理
callback: () => {
data.lines = this.props.consumeStore.selectedLines
this.setState({ data }, () => {
this.formRef.checkCanSubmit()
})
},
})
}
/**
* @description: 费用明细跳转前处理
* @param {*}
* @return {*}
*/
feeBeforeHandler() {
const { data } = this.state
this.props.navigation.navigate('ConsumeFee', {
feeLines: R.clone(data.feeLines),
callback: feeLines => {
data.feeLines = R.clone(feeLines)
this.setState({ data }, () => {
this.formRef.checkCanSubmit()
})
},
})
}
/**
* @description: 提交
*/
async submitHandler() {
const { data, submitting } = this.state
data.lines = R.map(R.assoc('consumedQuantity', 1))(data.lines)
const res = await this.props.consumeStore.submit({ data })
if (res.errorCode === 0) {
this.props.navigation.navigate('Success', {
orderNumber: res.consumeOrderNumber,
title: '器械消耗',
})
} else {
show(res.errorMsg)
}
}
render() {
const { formItems, data, scrollable } = this.state
const { navigation } = this.props
const title = navigation.getParam('title', '骨科智慧仓')
return (
<View style={g(styles, 'container', 'bg-gray')}>
<Header
title={title}
backCallback={() => {
navigation.goBack()
}}
/>
{/* form表单 */}
<Form
fields={formItems}
data={data}
onChange={this.setData}
ref={ref => (this.formRef = ref)}
submitHandler={this.submitHandler}
/>
</View>
)
}
}
export default inject('sysStore', 'userStore', 'orgStore', 'consumeStore')(observer(Consume))
@import '../../assets/styles/base.styl'
@import '../../assets/styles/variable.styl'
font_size = 18px
.container
flex 1
background-color home_background_color
.bd-inner
align-items center
padding-bottom 30px
.list
padding 20px
width 100%
.form
background-color #fff
border-radius 4px
padding 0 20px
margin-bottom 20px
&-item
padding 15px 0
border-bottom-color rgba(224, 224, 224, 0.5)
border-bottom-width 1px
flex-direction row
justify-content space-between
&__remove
&-text
font-size font_size
font-family font_family_semibold
color primary_color
&__select
flex 1
flex-direction row
justify-content flex-end
align-items center
&-text
font-size font_size
font-family font_family_regular
color second_text_color
&-arrow
width 18px
height @width
&__value
font-size font_size
font-family font_family_regular
color second_text_color
&__remark
border-bottom-width 0
flex-direction column
&-value
height 80px
&__label
font-size font_size
color first_text_color
padding-bottom 15px
&-label
font-size 18px
font-family font_family_semibold
.red
color red
.btn
width 342px
height 52px
border-radius 10px
background-color btn_sub_color
overflow hidden
@extend .center
@extend .middle
&__text
color rgba(255, 255, 255, 100)
font-size 17px
font-family font_family_semibold
.add-btn
width 374px
background-color btn_color
&__text
color primary_color
.ft
height 88px
width 100%
background-color #fff
@extend .middle
@extend .center
/*
* @FilePath: /BoneHouse_Business_APP/src/pages/consume/fee.tsx
* @Author: peii
* @Date: 2021-05-20 22:57:01
* @Vision: 1.0
* @Description: 费用明细页面
*
* @Revision:
*
*/
import React, { Component, useState } from 'react'
import { View, Text, FlatList, TouchableOpacity, Image, TextInput, ScrollView } from 'react-native'
import { inject, observer } from 'mobx-react'
import { toJS } from 'mobx'
import { IFee } from 'bonehouse'
import * as R from 'ramda'
import Header from '../../components/header/header'
import { BottomModal } from '../../components/modals/base/bottom'
import { SelectModal } from '../../components/form/select-modal'
import { g, isBlank, isNotBlank, show, genPid } from '../../utils/utils'
import styles from './fee.styl'
type IProps = {
sysStore: {
sysValueSets: {
SUR_FEE_TYPE: any[]
}
}
}
class Fee extends Component<IProps> {
state = {
feeLines: [
{
fid: genPid(),
feeType: '',
feeAmount: '',
remark: '',
},
],
fee: {
feeType: '',
feeAmount: '',
remark: '',
},
visible: false,
currentFeeType: '',
currentIndex: -1,
feeTypes: [],
}
constructor(props: IProps) {
super(props)
this.onBackHandler = this.onBackHandler.bind(this)
this.onFeeTypeChnageHandler = this.onFeeTypeChnageHandler.bind(this)
this.textInputHandler = this.textInputHandler.bind(this)
this.addFeeHandler = this.addFeeHandler.bind(this)
this.submitHandler = this.submitHandler.bind(this)
}
componentDidMount() {
const { feeLines } = this.props.navigation.state.params
if (isNotBlank(feeLines)) {
this.setState({ feeLines })
}
setTimeout(() => {
const feeTypes = R.compose(
R.map(
R.applySpec({
label: R.prop('valueName'),
value: R.prop('valueCode'),
}),
),
R.pathOr([], ['sysStore', 'sysValueSets', 'SUR_FEE_TYPE']),
)(this.props)
this.setState({ feeTypes })
}, 0)
}
/**
* @description: 返回操作
* @param {*}
* @return {*}
*/
onBackHandler() {
this.props.navigation.goBack()
}
openModal(item: IFee, index: number) {
this.setState({ visible: true, currentIndex: index, currentFeeType: item.feeType })
}
/**
* @description: 选择回调
* @param {*} value
* @return {*}
*/
onFeeTypeChnageHandler(value) {
const { feeLines, currentIndex } = this.state
feeLines[currentIndex].feeType = value
this.setState({ feeLines })
}
/**
* @description: 输入操作
* @param {*} text
* @param {*} index
* @param {*} key
* @return {*}
*/
textInputHandler(text: string, index: number, key: string) {
const { feeLines } = this.state
if (key === 'feeAmount' && isNaN(text)) {
return show('请输入数字')
}
feeLines[index][key] = text
this.setState({ feeLines })
}
/**
* @description: 添加消耗明细
* @param {*}
* @return {*}
*/
addFeeHandler() {
let { feeLines, fee } = this.state
for (const i in feeLines) {
const fee = feeLines[i]
if (R.any(isBlank, [fee.feeAmount, fee.feeType])) {
return show(`请先填写费用明细(${Number(i) + 1})的类型和金额`)
}
}
fee.fid = genPid()
feeLines = R.append(R.clone(fee), feeLines)
this.setState({ feeLines }, () => {
setTimeout(() => {
this.scrollRef.scrollToEnd({ animated: true })
}, 100)
})
}
/**
* @description: 删除一项
* @param {*} index
* @return {*}
*/
removeItemHandler(index) {
let { feeLines } = this.state
if (R.length(feeLines) === 1) {
return show('至少添加一项费用明细')
}
feeLines = R.remove(index, 1, feeLines)
this.setState({ feeLines })
}
/**
* @description: 选择显示
* @param {*} value
* @return {*}
*/
_text(value: string) {
return R.compose(
R.propOr('请选择', 'label'),
R.find(R.propEq('value', value)),
)(this.state.feeTypes)
}
/**
* @description: 确认返回
* @param {*}
* @return {*}
*/
submitHandler() {
const { state, goBack } = this.props.navigation
const { callback } = state.params
callback && callback(this.state.feeLines)
goBack()
}
/**
* @description: 渲染单项
* @param {*} item
* @param {*} index
* @return {*}
*/
_renderItem({ item, index }: { item: IFee; index: number }) {
return (
<View style={g(styles, 'form')}>
<View style={g(styles, 'form-item')}>
<Label label={`费用明细(${index + 1})`} />
<TouchableOpacity
style={g(styles, 'form-item__remove')}
activeOpacity={0.5}
onPress={() => this.removeItemHandler(index)}
>
<Text style={g(styles, 'form-item__remove-text')}>删除</Text>
</TouchableOpacity>
</View>
<View style={g(styles, 'form-item')}>
<Label label="费用类型" required={true} />
<TouchableOpacity
style={g(styles, 'form-item__select')}
activeOpacity={0.8}
onPress={() => this.openModal(item, index)}
>
<Text style={g(styles, 'form-item__select-text')}>{this._text(item.feeType)}</Text>
<Image
style={g(styles, 'form-item__select-arrow')}
source={require('../../assets/images/arr_rig.png')}
/>
</TouchableOpacity>
</View>
<View style={g(styles, 'form-item')}>
<Label label="费用金额" required={true} />
<TextInput
keyboardType="numeric"
defaultValue={item.feeAmount}
placeholder="请输入"
style={g(styles, 'form-item__value')}
onChangeText={text => {
this.textInputHandler(text, index, 'feeAmount')
}}
/>
</View>
<View style={g(styles, 'form-item', 'form-item__remark')}>
<Text style={g(styles, 'form-item__label')}>备注</Text>
<TextInput
defaultValue={item.remark}
placeholder="请输入备注信息"
multiline={true}
style={g(styles, 'form-item__value', 'form-item__remark-value')}
onChangeText={text => {
this.textInputHandler(text, index, 'remark')
}}
/>
</View>
</View>
)
}
render() {
const { feeLines, visible, currentFeeType, feeTypes } = this.state
return (
<View style={g(styles, 'container')}>
<Header title="器械消耗 - 费用明细" backCallback={this.onBackHandler} />
<ScrollView style={g(styles, 'bd')} ref={ref => (this.scrollRef = ref)}>
<View style={g(styles, 'bd-inner')}>
<FlatList
style={g(styles, 'list')}
data={feeLines}
renderItem={this._renderItem.bind(this)}
keyExtractor={item => R.toString(item.fid)}
/>
<TouchableOpacity
style={g(styles, 'btn', 'add-btn')}
activeOpacity={0.8}
onPress={this.addFeeHandler}
>
<Text style={g(styles, 'btn__text', 'add-btn__text')}>+添加</Text>
</TouchableOpacity>
</View>
</ScrollView>
<View style={g(styles, 'ft')}>
<TouchableOpacity
style={[
g(styles, 'btn'),
{ shadowColor: '#ccc', shadowOffset: { height: -6 }, shadowOpacity: 0.3 },
]}
onPress={this.submitHandler}
>
<Text style={g(styles, 'btn__text')}>确定费用</Text>
</TouchableOpacity>
</View>
{/* 选择器弹窗 */}
<SelectModal
visible={visible}
data={feeTypes}
headerHeight={0}
value={currentFeeType}
onClose={() => this.setState({ visible: false })}
onChange={this.onFeeTypeChnageHandler}
/>
</View>
)
}
}
/**
* @description:
* @param {*} required
* @param {*} label
* @return {*}
*/
function Label({ required, label }) {
return (
<Text style={g(styles, 'form-label')}>
{!!required && <Text style={g(styles, 'red', 'pr5')}>*</Text>}
<Text>{label}</Text>
</Text>
)
}
export default inject('consumeStore', 'sysStore')(observer(Fee))
@import '../../../assets/styles/base.styl'
@import '../../../assets/styles/variable.styl'
.filter
flex 1
background-color home_background_color
width 100%
z-index 999
&-bd
// padding 0 20px
height 310px
padding-bottom 20px
z-index 999
&__inner
padding 20px
z-index 999
&-ft
@extend .row
position absolute
bottom 0
width 100%
height 40px
background-color #fff
justify-content space-between
align-items center
.form
&-item
@extend .row
align-items center
width 100%
height 40px
margin-bottom 15px
&__input
flex 1
height 100%
text-align right
background-color #fff
padding 0 10px
color second_text_color
&__radio
@extend .row
&-active
background-color #E7F1FD
&-text
color second_text_color
&-active
color #007EFF
&-item
background-color #fff
padding 10px 20px
margin-right 20px
&-label
width 120px
.btn
width 50%
align-items center
justify-content center
background-color #E7F1FD
height 100%
border-right-width 1px
border-top-width 1px
border-color #ddd
&-text
color primary_color
font-size second_text_size
/*
* @FilePath: /BoneHouse_Hospital_APP/src/pages/hospital_order/components/plan_filter_modal.tsx
* @Author: peii
* @Date: 2021-06-07 14:37:49
* @Vision: 1.0
* @Description: 筛选
*
*/
// @ts-nocheck
import React, { Component } from 'react'
import { View, Text, ScrollView, Platform, TextInput, TouchableOpacity } from 'react-native'
import * as R from 'ramda'
import { FieldType } from '../../../enums'
import { TopModal } from '../../../components/modals/base/top'
import { g } from '../../../utils/utils'
import styles from './plan_filter_modal.styl'
type IProps = {
visible: boolean
onClose: Function
}
type IState = {
action: number
}
const FormComponents = {
[FieldType.RADIO]: FormRadio,
[FieldType.TEXT]: FormInput,
}
export default class PlanFilterModal extends Component<IProps> {
state = {
action: 0,
filterData: {
status: ['UNREFERENCED'],
},
filterItems: [
{
field: 'status',
label: '状态',
type: FieldType.RADIO,
options: [
{
value: 'UNREFERENCED',
label: '未引用',
},
{
value: 'REFERENCED',
label: '已引用',
},
],
},
{
field: 'brxm',
label: '病人姓名',
type: FieldType.TEXT,
},
{
field: 'brxb',
label: '病人性别',
type: FieldType.RADIO,
options: [
{
value: '1',
label: '男',
},
{
value: '2',
label: '女',
},
],
},
{
field: 'zyh',
label: '住院号',
type: FieldType.TEXT,
},
{
field: 'sqks',
label: '科室',
type: FieldType.TEXT,
},
{
field: 'ssys',
label: '医生',
type: FieldType.TEXT,
},
{
field: 'ssmc',
label: '手术名称',
type: FieldType.TEXT,
},
{
field: 'zvsx',
label: '备注',
type: FieldType.TEXT,
},
],
}
constructor(props: IProps) {
super(props)
this.onClose = this.onClose.bind(this)
this.setData = this.setData.bind(this)
this.resetHandler = this.resetHandler.bind(this)
this.filterHandler = this.filterHandler.bind(this)
}
/**
* @description: 输入
* @param {*} key 输入项
* @param {*} value 输入值
* @return {*}
*/
setData(key: string, value: any) {
const { filterData } = this.state
filterData[key] = value
this.setState({ filterData })
}
/**
* 获取过滤信息
* @returns
*/
getData() {
return this.state.filterData
}
/**
* @description: 重置操作
* @param {*}
* @return {*}
*/
resetHandler() {
this.setState({ filterData: { status: ['UNREFERENCED'] } }, () => {
this.props.filterHandler &&
this.props.filterHandler({
status: ['UNREFERENCED'],
})
this.onClose()
})
}
/**
* @description: 确定
* @param {*}
* @return {*}
*/
filterHandler() {
const { filterData } = this.state
this.props.filterHandler && this.props.filterHandler(filterData)
this.onClose()
}
/**
* @description: 关闭
* @param {*}
* @return {*}
*/
onClose() {
this.props.onClose && this.props.onClose()
}
render() {
const { visible } = this.props
const { action, filterData, filterItems } = this.state
return (
<TopModal visible={visible} action={action} onClose={this.onClose} initTop={40}>
<View style={g(styles, 'filter')}>
<View style={g(styles, 'filter-bd')}>
<ScrollView style={g(styles, 'filter-bd__inner')}>
{filterItems.map(item => {
const FormComponent = FormComponents[item.type] || FormInput
return (
<View style={g(styles, 'filter-item')} key={item.field}>
<FormComponent item={item} value={filterData[item.field]} onChange={this.setData} />
</View>
)
})}
</ScrollView>
</View>
<View style={g(styles, 'filter-ft')}>
<TouchableOpacity style={g(styles, 'btn')} activeOpacity={0.8} onPress={this.resetHandler}>
<Text style={g(styles, 'btn-text')}>重置</Text>
</TouchableOpacity>
<TouchableOpacity style={g(styles, 'btn')} activeOpacity={0.8} onPress={this.filterHandler}>
<Text style={g(styles, 'btn-text')}>确定</Text>
</TouchableOpacity>
</View>
</View>
</TopModal>
)
}
}
function Title({ title }) {
return <Text style={g(styles, 'form-label')}>{title}</Text>
}
function FormInput({ item, value, onChange }) {
return (
<View style={g(styles, 'form-item')}>
<Title title={item.label} />
<TextInput
placeholder="请输入"
onChangeText={text => onChange(item.field, text)}
style={g(styles, 'form-item__input')}
defaultValue={value}
/>
</View>
)
}
/**
* @description:
* @param {*} item
* @param {*} value
* @return {*}
*/
function FormRadio({ item, value, onChange }) {
return (
<View style={g(styles, 'form-item')}>
<Title title={item.label} />
<View style={g(styles, 'form-item__radio')}>
{item.options.map(option => {
return (
<TouchableOpacity
key={option.value}
activeOpacity={0.8}
style={g(styles, {
'form-item__radio-item': true,
'form-item__radio-active': R.includes(option.value, value || []),
})}
onPress={() => {
let values = R.clone(value || [])
if (R.includes(option.value, values)) {
values = R.compose(R.remove(R.__, 1, values), R.findIndex(R.equals(option.value)))(values)
} else {
values = R.append(option.value, values)
}
onChange(item.field, values)
}}
>
<Text
style={g(styles, {
'form-item__radio-text': true,
'form-item__radio-text-active': R.includes(option.value, value || []),
})}
>
{option.label}
</Text>
</TouchableOpacity>
)
})}
</View>
</View>
)
}
@import '../../assets/styles/base.styl'
@import '../../assets/styles/variable.styl'
.container
background-color home_background_color
flex 1
.body
flex 1
.filter
// 安卓加了这个就不能点了
&-ios
z-index 99
&-bar
@extend .row
@extend .center
height 40px
padding 0 20px
background-color home_background_color
border-bottom-width 1px
border-bottom-color #ddd
&__text
font-size 14px
color second_text_color
&__icon
width 16px
height @width
margin-left 8px
.plan-list
padding 20px
width 100%
.item
@extend .row
background-color #fff
padding 15px
margin-bottom 20px
@extend .center
&-left
width 40px
&-middle
flex 1
&-right
width 100px
&-text
font-family font_family_regular
font-size 14px
color second_text_color
padding-bottom 5px
&-name
font-size 18px
font-family font_family_semibold
&__remark
font-size 12px
padding-bottom 0
&-status
font-size 18px
color second_text_color
&__active
color primary_color
&-selected
width 18px
height 18px
&__icon
width 18px
height @width
// @ts-nocheck
import React, { Component } from 'react'
import { View, Text, FlatList, Image, TouchableOpacity, Platform } from 'react-native'
import { IPlan } from 'bonehouse'
import { INavigation } from 'navigation'
import { connect } from 'react-redux'
import * as R from 'ramda'
import { GetRequest } from '../../../app/network/RequestUtils'
import { getUrlParams } from '../../../app/utils/Utils'
import LoadingModel from '../../../app/containers/common/listDataComponent/LoadingModel'
import Resolution from '../../components/common/Resolution'
import Form from '../../components/form'
import Header from '../../components/header/header'
import { g, isBlank, isNotBlank, show, getHeaderHeight } from '../../utils/utils'
import FilterModal from './components/plan_filter_modal'
import styles from './plan.styl'
export const gender = R.cond([
[R.equals('1'), R.always('男')],
[R.equals('2'), R.always('女')],
[R.T, R.always('未知')],
])
export const status = R.cond([
[R.equals('REFERENCED'), R.always('已引用')],
[R.T, R.always('未引用')],
])
type IProps = {
token: string
userInfo: any
global_domain_config: string
navigation: INavigation
}
type IState = {
modalVisible: boolean
data: IPlan[]
originData: IPlan[]
}
class SurgeryPlan extends Component<IProps, IState> {
state = {
loading: false,
modalVisible: false,
data: [],
originData: [],
}
constructor(props) {
super(props)
this.onClose = this.onClose.bind(this)
this.selectHandler = this.selectHandler.bind(this)
this.filterHandler = this.filterHandler.bind(this)
}
componentDidMount() {
this.getData()
}
/**
* @description: 获取手术规划
* @param {*}
* @return {*}
*/
async getData() {
try {
const params = {
access_token: this.props.token,
}
this.loadingRef.show()
const res = await GetRequest(
this.props.global_domain_config,
getUrlParams(`/surgery/gkls_sur_plan/search`, params),
)
console.log(res)
this.loadingRef.hide()
if (res.error_code !== 0) return
const originData = R.compose(R.clone, R.pathOr([], ['data', 'gkls_sur_plans']))(res)
this.setState({ originData }, () => {
const filterData = this.filterModal.getData()
this.filterHandler(filterData)
})
} catch (error) {
this.loadingRef.hide()
console.log(error)
show('请求失败')
}
}
/**
* @description: 选择操作
* @param {*} item
* @return {*}
*/
selectHandler(item) {
const { goBack, state } = this.props.navigation
state.params.callback && state.params.callback(item)
goBack()
}
onClose() {
this.setState({ modalVisible: false })
}
/**
* @description: 过滤
* @param filterData
*/
filterHandler(filterData) {
const { originData } = this.state
let data = R.clone(originData)
R.compose(
R.map(key => {
const filter = filterData[key]
if (isBlank(filter)) return
if (R.type(filter) === 'Array') {
data = R.filter(R.compose(R.includes(R.__, filter), R.prop(key)))(data)
} else if (R.type(filter) === 'String') {
const regExp = new RegExp(filter, 'g')
data = R.filter(R.compose(R.test(regExp), R.prop(key)))(data)
}
}),
R.keys,
)(filterData)
this.setState({ data })
}
renderItem({ item }) {
const sourceId = this.props.navigation.getParam('source_id', '')
return (
<TouchableOpacity
style={g(styles, 'item')}
activeOpacity={0.8}
onPress={() => {
this.selectHandler(item)
}}
>
<View style={g(styles, 'item-left')}>
<View style={g(styles, 'item-selected')}>
{R.equals(sourceId, item.id) ? (
<Image
style={g(styles, 'item-selected__icon')}
source={require('../../assets/images/radio_yes.png')}
></Image>
) : (
<Image
style={g(styles, 'item-selected__icon')}
source={require('../../assets/images/radio_no.png')}
></Image>
)}
</View>
</View>
<View style={g(styles, 'item-middle')}>
<Text style={g(styles, 'item-text', 'item-name')}>
{item.brxm} {gender(item.brxb)} {item.zyh}
</Text>
<Text style={g(styles, 'item-text', 'item-name__surgery')}>{item.ssmc}</Text>
<Text style={g(styles, 'item-text', 'item-name__surgery')}>
{item.sqks || '暂无科室'} {item.ssys || '暂无医生'}
</Text>
<Text style={g(styles, 'item-text', 'item-name__time')}>
{item.ssDate || item.ssTime ? item.ssDate + ' ' + item.ssTime : '暂无手术时间'}
</Text>
<Text style={g(styles, 'item-text', 'item-name__remark')}>备注:{item.sqzd || '无'}</Text>
<Text style={g(styles, 'item-text', 'item-name__remark')}>{item.zysx || '无'}</Text>
</View>
<Text
style={g(styles, {
'item-status': true,
'item-status__active': item.status === 'REFERENCED',
})}
>
{status(item.status)}
</Text>
</TouchableOpacity>
)
}
render() {
const { modalVisible, data } = this.state
return (
<View style={g(styles, 'container')}>
<Resolution.FixWidthView>
<Header
title="手术规划"
backCallback={() => {
this.props.navigation.goBack()
}}
/>
<LoadingModel ref={ref => (this.loadingRef = ref)} />
<View style={[g(styles, 'body')]}>
<View style={g(styles, { filter: true, 'filter-ios': Platform.OS === 'ios' })}>
<TouchableOpacity
style={g(styles, 'filter-bar')}
activeOpacity={0.8}
onPress={() => {
this.setState({ modalVisible: !modalVisible })
}}
>
<Text style={g(styles, 'filter-bar__text')}>筛选</Text>
<Image
style={g(styles, 'filter-bar__icon')}
source={require('../../assets/images/arr_bom.png')}
></Image>
</TouchableOpacity>
{/* 过滤弹窗 */}
<FilterModal
visible={modalVisible}
onClose={this.onClose}
filterHandler={this.filterHandler}
ref={ref => (this.filterModal = ref)}
/>
</View>
<FlatList
style={g(styles, 'plan-list')}
data={data}
renderItem={this.renderItem.bind(this)}
keyExtractor={item => item.id}
></FlatList>
</View>
</Resolution.FixWidthView>
</View>
)
}
}
const mapStateToProps = state => {
return {
userInfo: state.login.userInfo,
token: state.login.token,
global_domain_config: state.login.global_domain_config,
}
}
const mapDispatchToProps = dispatch => {
return {}
}
export default connect(mapStateToProps, mapDispatchToProps)(SurgeryPlan)
@import '../../assets/styles/base.styl'
@import '../../assets/styles/variable.styl'
.container
flex 1
background-color home_background_color
/*
* @FilePath: /BoneHouse_Hospital_APP/src/pages/hospital_order/self.tsx
* @Author: peii
* @Date: 2021-06-06 13:03:07
* @Vision: 1.0
* @Description: 医院版自助下单(东方医院)
*
*/
// @ts-nocheck
import React, { Component } from 'react'
import { View, SafeAreaView } from 'react-native'
import { IPlan } from 'bonehouse'
import { INavigation } from 'navigation'
import { connect } from 'react-redux'
import * as R from 'ramda'
import Resolution from '../../components/common/Resolution'
import Form from '../../components/form'
import { FieldType, SelectMode } from '../../enums'
import Header from '../../components/header/header'
import { g, getFormItem, isBlank, show } from '../../utils/utils'
import LocalVariable from '../../../app/containers/common/LocalVariable'
import { PostRequest } from '../../../app/network/RequestUtils'
import NotEnoughModel from '../../../app/containers/common/NotEnoughModel'
import { getUrlParams } from '../../../app/utils/Utils'
import { gender } from './plan'
import styles from './self.styl'
type IProps = {
navigation: INavigation
global_domain_config: string
setSelfInitData: Function
}
class HospitalSelfOrder extends Component<IProps> {
state = {
showNotEnogPop: false, // 库存不足弹窗
notEnoughItemsList: [], // 库存不足数据
data: {
seller_code: this.props.userInfo.user_name,
take_cert_flag: 'Y',
replace_item_flag: 'N',
Caller: 'dingding',
},
formItems: [
{
field: 'seller_code',
label: '销售员',
type: FieldType.SELECT,
options: [
{
label: this.props.userInfo.person_name || this.props.userInfo.user_name,
value: this.props.userInfo.user_name,
},
],
placeholder: '请选择',
rules: [{ required: true, message: '请选择医生' }],
disabled: true,
},
{
field: 'source_id',
label: '手术规划',
type: FieldType.SELECT,
selectMode: SelectMode.PAGE,
placeholder: '请选择',
options: [],
rules: [{ required: true, message: '请选择手术规划' }],
refrence: ['doctorCode'],
customHandler: this.surgeryPlanBeforeHandler.bind(this, 'source_id'),
},
{
field: 'surgery_date',
label: '需求时间',
type: FieldType.DATE,
dateMode: 'datetime',
placeholder: '请选择',
},
{
field: 'lines',
label: '选择产品',
type: FieldType.SELECT,
selectMode: SelectMode.PAGE,
placeholder: '请选择',
options: [],
rules: [{ required: true, message: '请选择产品' }],
refrence: ['source_id'],
customHandler: this.linesBeforeHandler.bind(this),
},
{
field: 'take_cert_flag',
label: '需要携带合格证',
type: FieldType.RADIO,
options: [
{ label: '是', value: 'Y' },
{ label: '否', value: 'N' },
],
},
{
field: 'replace_item_flag',
label: '同意替换器械包',
type: FieldType.RADIO,
options: [
{
label: '是',
value: 'Y',
},
{
label: '否',
value: 'N',
},
],
},
],
}
constructor(props) {
super(props)
this.setData = this.setData.bind(this)
this.submitHandler = this.submitHandler.bind(this)
}
componentWillUnmount() {
this.props.setSelfInitData()
}
/**
* @description: 设置修改值
* @param {*}
* @return {*}
*/
setData(key: string, value: any) {
return new Promise<any>((resolve, reject) => {
const { data, formItems } = this.state
data[key] = value
this.setState({ data }, () => {
const item = getFormItem(formItems, key)
item && item.callback && item.callback()
resolve()
})
})
}
/**
* @description: 手术规划选择处理
* @param {*} key
* @return {*}
*/
surgeryPlanBeforeHandler(key: string) {
const { data } = this.state
this.props.navigation.navigate('SurgeryPlan', {
doctorCode: data.doctorCode,
source_id: data.source_id,
callback: (plan: IPlan) => {
const surgery_date = (plan.ssDate && plan.ssTime && plan.ssDate + ' ' + plan.ssTime) || undefined
const selectData = {
source_id: plan.id,
org_id: plan.orgId,
org_code: plan.org_code,
customer_id: plan.customerId,
customer_code: plan.customercode,
customer_site_id: plan.customerSiteId,
bill_to_site_id: plan.customerSiteId,
ship_to_site_id: plan.customerSiteId,
surgery_date: surgery_date,
patient_name: plan.brxm, // 患者姓名
patient_gender: plan.brxb, // 性别
patient_id: plan.zyh, // 病历号
hospitalization_number: plan.zyh, // 病历号
remark: plan.zysx, // 备注信息
sqks: plan.sqks,
ssys: plan.ssys,
sqzd: plan.sqzd,
ssmc: plan.ssmc,
}
let { data, formItems } = this.state
data = Object.assign({}, data, selectData)
const item = R.find(R.propEq('field', key))(formItems)
item.options = [
{
value: plan.id,
label: plan.brxm + ' ' + gender(plan.brxb) + ' ' + plan.zyh,
},
]
this.setState({ data, formItems }, () => {
this.formRef.checkCanSubmit()
})
},
})
}
/**
* @description: 选择产品
* @param {*}
* @return {*}
*/
linesBeforeHandler() {
const { data } = this.state
this.props.navigation.navigate('ChooseProductPage', {
title: '选择产品',
selfData: {
org_code: data.org_code,
},
productCallBack: items => {
const { data, formItems } = this.state
const option = {
value: 'lineTmp',
label: '',
}
items &&
items.map(item => {
if (!!item.selectedQuantity) {
option.label += `【${item.supplier_short_name}】`
}
})
const item = R.find(R.propEq('field', 'lines'))(formItems)
if (isBlank(option.label)) {
data.lines = ''
data.linesData = []
item.options = []
} else {
data.lines = option.value
data.linesData = R.clone(items)
item.options = [option]
}
this.setState({ data, formItems }, () => {
this.formRef.checkCanSubmit()
})
},
})
}
/**
* @description: 获取产品
* @param {*}
* @return {*}
*/
getSubLines() {
let { data } = this.state
// 修改提交的行数据
let local_lines = R.clone(data.linesData)
let res_lines = []
let showPackageTip = false
local_lines.forEach(sup_item => {
if (
sup_item[LocalVariable.SELECTED_QUQNTITY] > 0 &&
sup_item.leftOptionList &&
sup_item.leftOptionList.length > 0
) {
sup_item.leftOptionList.map(lef_item => {
// let select_arr = lef_item[LocalVariable.SELECTED_DATA_ARR]
let select_arr = lef_item.selectedArr || []
if (lef_item[LocalVariable.SELECTED_QUQNTITY] > 0 && select_arr && select_arr.length > 0) {
if (lef_item.category_code === LocalVariable.SURGICAL_TEMPLATE) {
// 手术套包
select_arr.forEach(sel_item => {
let template_number = sel_item.template_number
if (
sel_item[LocalVariable.CHILDREN_LINE_NAME] &&
sel_item[LocalVariable.CHILDREN_LINE_NAME].length > 0
) {
sel_item[LocalVariable.CHILDREN_LINE_NAME].forEach(chi_item => {
if (chi_item[LocalVariable.LINE_OPTIONS] && chi_item[LocalVariable.LINE_OPTIONS].length > 0) {
chi_item[LocalVariable.LINE_OPTIONS].forEach(lin_item => {
if (
lin_item[LocalVariable.SELECTED_DATA_ARR] &&
lin_item[LocalVariable.SELECTED_DATA_ARR].length > 0
) {
lin_item[LocalVariable.SELECTED_DATA_ARR].forEach(sel_item => {
if (sel_item[LocalVariable.QUANTITY_FIELD] > 0) {
// sel_item['template_number'] = template_number // 暂时不用
sel_item[LocalVariable.PLAN_QUANTITY] = sel_item[LocalVariable.QUANTITY_FIELD]
res_lines.push(sel_item)
}
})
}
})
}
})
}
})
} else if (
lef_item.category_code === LocalVariable.NAIL_BOX ||
lef_item.category_code === LocalVariable.EQUIPMENT_BAG
) {
// 钉盒/器械包
if (lef_item.category_code === LocalVariable.EQUIPMENT_BAG) {
showPackageTip = true
}
select_arr.forEach(sel_item => {
if (sel_item[LocalVariable.QUANTITY_FIELD] > 0) {
// sel_item['prefer_serial_number'] = sel_item.serial_number // 暂时不用
sel_item['line_remark'] = sel_item.serial_number
sel_item[LocalVariable.PLAN_QUANTITY] = sel_item[LocalVariable.QUANTITY_FIELD]
res_lines.push(sel_item)
}
})
} else if (lef_item.category_code === LocalVariable.SCATTERED_EQUIPMENT) {
// 零散器械
select_arr.forEach(sel_item => {
if (sel_item[LocalVariable.QUANTITY_FIELD] > 0) {
sel_item[LocalVariable.PLAN_QUANTITY] = sel_item[LocalVariable.QUANTITY_FIELD]
res_lines.push(sel_item)
}
})
} else {
// 耗材
if (select_arr[0].details && select_arr[0].details.length > 0) {
// 大-中-小类
select_arr.forEach(sel_item => {
sel_item.details.forEach(end_item => {
if (end_item[LocalVariable.QUANTITY_FIELD] > 0) {
end_item[LocalVariable.PLAN_QUANTITY] = end_item[LocalVariable.QUANTITY_FIELD]
res_lines.push(end_item)
}
})
})
} else {
// 大类-小类
select_arr.forEach(sel_item => {
if (sel_item[LocalVariable.QUANTITY_FIELD] > 0) {
sel_item[LocalVariable.PLAN_QUANTITY] = sel_item[LocalVariable.QUANTITY_FIELD]
res_lines.push(sel_item)
}
})
}
}
}
})
}
})
let line_obj = {}
let end_lines = []
// 汇总同类物料
res_lines.map(line_it => {
if (!line_obj[line_it.item_code]) {
line_obj[line_it.item_code] = line_it.item_code
end_lines.push(line_it)
} else {
end_lines.forEach(function (fil_li) {
if (fil_li.item_code === line_it.item_code) {
if (line_it['line_remark']) {
fil_li.line_remark = line_it.line_remark
}
fil_li[LocalVariable.QUANTITY_FIELD] += line_it[LocalVariable.QUANTITY_FIELD]
fil_li[LocalVariable.PLAN_QUANTITY] = fil_li[LocalVariable.QUANTITY_FIELD]
}
})
}
})
end_lines.map(function (line_obj, line_ind) {
line_obj['line_number'] = line_ind + 1
})
return end_lines
}
/**
* @description: 提交订单
* @param {*}
* @return {*}
*/
async submitHandler() {
const { data } = this.state
const params = R.clone(data)
params.lines = this.getSubLines()
delete params.linesData
const global_domain_config = this.props.global_domain_config
const access_token = this.props.token
try {
let res = await PostRequest(
global_domain_config,
getUrlParams('/surgery/collect_order/via_data/create', {
access_token,
}),
{ data: params },
)
if (res.error_code === 0) {
if (res.data.create_success == 'N') {
// 打开库存不足弹窗
this.setState(
{
notEnoughItemsList: res.data.not_enough_items_list,
},
() => {
// 解决 IOS 弹窗显示问题
setTimeout(() => {
this.setState({
showNotEnogPop: true,
})
}, 500)
},
)
} else if (res.data.create_success == 'Y') {
// 打开下单成功页面
this.props.setSelfInitData()
const title = this.props.navigation.getParam('title')
this.props.navigation.navigate('SubSuccPage', {
title: `${title} - 下单成功`,
orderNumber: res.data.survey_collect_number,
})
}
} else {
show(res.error_msg || '请求异常,请重试')
}
} catch (error) {
console.log(error)
show(error.error_msg || '请求异常,请重试')
}
}
/**
* 返回库存不足弹窗
* @returns
*/
renderNotEnoughModel() {
let { notEnoughItemsList, showNotEnogPop } = this.state
return (
<SafeAreaView style={styles.item_container}>
<NotEnoughModel
not_enough_items_list={notEnoughItemsList}
callback={() => this.handleNotEnoughCallBack()}
show={showNotEnogPop}
closeModal={show => this.handleNotEnoughCloseModal(show)}
/>
</SafeAreaView>
)
}
handleNotEnoughCallBack() {
let { data } = this.state
this.setState(
{
data: {
...data,
force_balance_check_flag: 'N',
},
},
() => {
this.formRef.submitHandler()
},
)
}
handleNotEnoughCloseModal(show) {
this.setState({
showNotEnogPop: show,
})
}
render() {
const { data, formItems } = this.state
const { navigation } = this.props
const title = navigation.getParam('title', '骨科智慧仓')
return (
<View style={g(styles, 'container')}>
<Resolution.FixWidthView>
<Header
title={title}
backCallback={() => {
this.props.navigation.goBack()
}}
></Header>
{/* 表单 */}
<Form
fields={formItems}
data={data}
onChange={this.setData}
ref={ref => (this.formRef = ref)}
submitHandler={this.submitHandler}
/>
</Resolution.FixWidthView>
{this.renderNotEnoughModel()}
</View>
)
}
}
const mapStateToProps = state => {
return {
userInfo: state.login.userInfo,
token: state.login.token,
global_domain_config: state.login.global_domain_config,
}
}
const mapDispatchToProps = dispatch => {
return {
setSelfInitData() {
dispatch({
type: 'SELF_INIT_DATA',
})
},
}
}
export default connect(mapStateToProps, mapDispatchToProps)(HospitalSelfOrder)
@import '../../assets/styles/base.styl'
@import '../../assets/styles/variable.styl'
.index
flex 1
background home_background_color
.biz
flex 1
&-view
flex-wrap wrap
flex-direction row
justify-content space-between
padding 40px
&-box
width 150px
height @width
border-radius 5px
background-color rgba(255, 255, 255, 1)
margin-bottom 40px
@extend .middle
@extend .center
&-name
color first_text_color
font-size 18px
font-family font_family_regular
padding-top 10px
/*
* @FilePath: /BoneHouse_Business_APP/src/pages/index/index.tsx
* @Author: peii
* @Date: 2021-04-24 22:45:15
* @Vision: 1.0
* @Description: 首页
*
* @Revision:
*
*/
import React, { Component } from 'react'
import { View, Text, TouchableOpacity, Image, ScrollView, RefreshControl } from 'react-native'
import slashScreen from 'react-native-splash-screen'
import { observer, inject } from 'mobx-react'
import { IFunction } from 'bonehouse'
import Resolution from '../../components/common/Resolution'
import Header from '../../components/header/header'
import { g } from '../../utils/utils'
import styles from './index.styl'
type IProps = {
store: {
token: string
functionIcons: any[]
getBizFuns: Function
setNavigation: Function
}
orgStore: {
getOrganizations: Function
}
}
class Index extends Component<IProps> {
state = {
refreshing: false,
}
constructor(props) {
super(props)
this.onRefresh = this.onRefresh.bind(this)
this.navigateToBizPage = this.navigateToBizPage.bind(this)
}
componentDidMount() {
slashScreen.hide()
this.props.store.setNavigation(this.props.navigation)
setTimeout(() => {
const { navigation, store, orgStore } = this.props
if (!store.token) {
return navigation.navigate('Signin')
}
orgStore.getOrganizations()
}, 0)
}
/**
* @description: 下拉刷新
* @param {*}
* @return {*}
*/
onRefresh() {
this.setState({ refreshing: true })
this.props.orgStore.getOrganizations().finally(() => this.setState({ refreshing: false }))
}
/**
* @description: 导航到功能页
* @param {*} fun
* @return {*}
*/
navigateToBizPage(fun: IFunction) {
const pages = {
MOBILE_BORROW_ORDER: 'QuickOrder',
MOBILE_SELF_HELP_ORDER: '',
MOBILE_CONSUMP_CONFIRMA: 'Consume',
MOBILE_DEVICE_INFORMATION: '',
MOBILE_TRANSFER_APPLICATION: '',
}
this.props.navigation.navigate(pages[fun.functionCode], { title: fun.functionName })
}
render() {
const { navigation, store } = this.props
const { refreshing } = this.state
const funs = store.getBizFuns()
return (
<View style={styles.index}>
<Header title="骨科智慧仓" back={false} />
<ScrollView
style={g(styles, 'biz')}
refreshControl={<RefreshControl refreshing={refreshing} onRefresh={this.onRefresh} />}
>
<View style={g(styles, 'biz-view')}>
{funs.map(fun => {
return (
<TouchableOpacity
key={fun.functionCode}
style={g(styles, 'biz-box')}
activeOpacity={0.6}
onPress={() => this.navigateToBizPage(fun)}
>
<Image
style={g(styles, 'biz-icon')}
source={store.functionIcons[fun.functionCode]}
/>
<Text style={g(styles, 'biz-name')}>{fun.functionName}</Text>
</TouchableOpacity>
)
})}
</View>
</ScrollView>
</View>
)
}
}
export default inject('store', 'orgStore')(observer(Index))
@import '../../assets/styles/base.styl'
@import '../../assets/styles/variable.styl'
.mine
flex 1
background-color home_background_color
.user
&-name
@extend .center
padding-top 10px
padding-bottom 10px
margin-bottom 20px
&__text
font-size second_text_size
color second_text_color
font-family font_family_semibold
.avatar
@extend .center
&-top
width 100%
height 150px
background-color primary_color
&-holder
background-color foundation_color
width 80px
height @width
border-radius half = 40px
margin-top -40px
padding 3px
box-shadow 0px 0px 1px #ddd
&-image
width 74px
height @width
border-radius 38px
.list
&-item
height 50px
&__img
width 20px
height @width
&-ex
width 18px
height @width
&__text
font-size second_text_size
border-bottom-width 0px
padding-left 10px
line-height 36px
/*
* @FilePath: /BoneHouse_Business_APP/src/pages/mine/mine.tsx
* @Author: peii
* @Date: 2021-04-24 22:45:15
* @Vision: 1.0
* @Description: 我的页面
*
* @Revision:
*
*/
import React, { Component } from 'react'
import { View, Text, ScrollView, Image, SafeAreaView } from 'react-native'
import { List } from '@ant-design/react-native'
import { inject, observer } from 'mobx-react'
import { g, isBlank } from '../../utils/utils'
import Header from '../../components/header/header'
import { DEFAULT_AVATAR } from '../../constants'
import styles from './mine.styl'
const Item = List.Item
type IProps = {
userStore: {
personName: string
gender: string
}
store: {
setToken: Function
}
}
class Mine extends Component<IProps> {
state = {
listItems: [
{
title: '历史订单',
thumb: require('../../assets/images/tab_his_def.png'),
extra: require('../../assets/images/arr_rig.png'),
arrow: 'empty',
onPressHandler: () => {},
},
{
title: '退出',
thumb: require('../../assets/images/exit.png'),
extra: require('../../assets/images/arr_rig.png'),
arrow: 'empty',
onPressHandler: () => {
this.exitHandler()
},
},
],
}
exitHandler() {
console.log('exitHandler')
this.props.store.setToken('')
this.props.navigation.navigate('Signin')
}
render() {
const { personName, gender } = this.props.userStore
const { listItems } = this.state
return (
<ScrollView style={g(styles, 'mine')}>
<View style={g(styles, 'mine')}>
<Header title="骨科智慧仓" back={false} />
<View style={g(styles, 'user')}>
<View style={g(styles, 'avatar')}>
<View style={g(styles, 'avatar-top')}></View>
<View style={g(styles, 'avatar-holder')}>
<Image source={DEFAULT_AVATAR} style={g(styles, 'avatar-image')} />
</View>
</View>
<View style={g(styles, 'user-name')}>
<Text style={g(styles, 'user-name__text')}>
{personName} {gender ? '‧ ' + gender : ''}
</Text>
</View>
</View>
<List style={g(styles, 'list')}>
{listItems.map(item => {
return (
<Item
key={item.title}
style={g(styles, 'list-item')}
thumb={<Image source={item.thumb} style={g(styles, 'list-item__img')} />}
extra={<Image source={item.extra} style={g(styles, 'list-item__img-ex')} />}
arrow={item.arrow}
onPress={item.onPressHandler}
>
<Text style={g(styles, 'list-item__text')}>{item.title}</Text>
</Item>
)
})}
</List>
</View>
</ScrollView>
)
}
}
export default inject('store', 'userStore')(observer(Mine))
@import '../../../assets/styles/base.styl'
@import '../../../assets/styles/variable.styl'
.filter
flex 1
background-color home_background_color
width 100%
z-index 999
&-bd
// padding 0 20px
height 310px
padding-bottom 20px
z-index 999
&__inner
padding 20px
z-index 999
&-ft
@extend .row
position absolute
bottom 0
width 100%
height 40px
background-color #fff
justify-content space-between
align-items center
.form
&-item
@extend .row
align-items center
width 100%
height 40px
margin-bottom 15px
&__input
flex 1
height 100%
text-align right
background-color #fff
padding 0 10px
color second_text_color
&__radio
@extend .row
&-active
background-color #E7F1FD
&-text
color second_text_color
&-active
color #007EFF
&-item
background-color #fff
padding 10px 20px
margin-right 20px
&-label
width 120px
.btn
width 50%
align-items center
justify-content center
background-color #E7F1FD
height 100%
border-right-width 1px
border-top-width 1px
border-color #ddd
&-text
color primary_color
font-size second_text_size
/*
* @FilePath: /BoneHouse_Hospital_APP/src/pages/order/components/plan_filter_modal.tsx
* @Author: peii
* @Date: 2021-06-07 14:37:49
* @Vision: 1.0
* @Description: 筛选
*
*/
// @ts-nocheck
import React, { Component } from 'react'
import { View, Text, ScrollView, Platform, TextInput, TouchableOpacity } from 'react-native'
import * as R from 'ramda'
import { FieldType } from '../../../enums'
import { TopModal } from '../../../components/modals/base/top'
import { g } from '../../../utils/utils'
import styles from './plan_filter_modal.styl'
type IProps = {
visible: boolean
onClose: Function
}
type IState = {
action: number
}
const FormComponents = {
[FieldType.RADIO]: FormRadio,
[FieldType.TEXT]: FormInput,
}
export default class PlanFilterModal extends Component<IProps> {
state = {
action: 0,
filterData: {
// status: ['UNREFERENCED'],
},
filterItems: [
// {
// field: 'status',
// label: '状态',
// type: FieldType.RADIO,
// options: [
// {
// value: 'UNREFERENCED',
// label: '未引用',
// },
// {
// value: 'REFERENCED',
// label: '已引用',
// },
// ],
// },
{
field: 'patientName',
label: '病人姓名',
type: FieldType.TEXT,
},
// {
// field: 'brxb',
// label: '病人性别',
// type: FieldType.RADIO,
// options: [
// {
// value: '1',
// label: '男',
// },
// {
// value: '2',
// label: '女',
// },
// ],
// },
// {
// field: 'zyh',
// label: '住院号',
// type: FieldType.TEXT,
// },
// {
// field: 'sqks',
// label: '科室',
// type: FieldType.TEXT,
// },
{
field: 'doctorName',
label: '医生姓名',
type: FieldType.TEXT,
},
{
field: 'surgeryName',
label: '手术名称',
type: FieldType.TEXT,
},
],
}
constructor(props: IProps) {
super(props)
this.onClose = this.onClose.bind(this)
this.setData = this.setData.bind(this)
this.resetHandler = this.resetHandler.bind(this)
this.filterHandler = this.filterHandler.bind(this)
}
/**
* @description: 输入
* @param {*} key 输入项
* @param {*} value 输入值
* @return {*}
*/
setData(key: string, value: any) {
const { filterData } = this.state
filterData[key] = value
this.setState({ filterData })
}
/**
* 获取过滤信息
* @returns
*/
getData() {
return this.state.filterData
}
/**
* @description: 重置操作
* @param {*}
* @return {*}
*/
resetHandler() {
this.setState({ filterData: {} }, () => {
this.props.filterHandler &&
this.props.filterHandler({
// status: ['UNREFERENCED'],
})
this.onClose()
})
}
/**
* @description: 确定
* @param {*}
* @return {*}
*/
filterHandler() {
const { filterData } = this.state
this.props.filterHandler && this.props.filterHandler(filterData)
this.onClose()
}
/**
* @description: 关闭
* @param {*}
* @return {*}
*/
onClose() {
this.props.onClose && this.props.onClose()
}
render() {
const { visible } = this.props
const { action, filterData, filterItems } = this.state
return (
<TopModal visible={visible} action={action} onClose={this.onClose} initTop={40}>
<View style={g(styles, 'filter')}>
<View style={g(styles, 'filter-bd')}>
<ScrollView style={g(styles, 'filter-bd__inner')}>
{filterItems.map(item => {
const FormComponent = FormComponents[item.type] || FormInput
return (
<View style={g(styles, 'filter-item')} key={item.field}>
<FormComponent item={item} value={filterData[item.field]} onChange={this.setData} />
</View>
)
})}
</ScrollView>
</View>
<View style={g(styles, 'filter-ft')}>
<TouchableOpacity style={g(styles, 'btn')} activeOpacity={0.8} onPress={this.resetHandler}>
<Text style={g(styles, 'btn-text')}>重置</Text>
</TouchableOpacity>
<TouchableOpacity style={g(styles, 'btn')} activeOpacity={0.8} onPress={this.filterHandler}>
<Text style={g(styles, 'btn-text')}>确定</Text>
</TouchableOpacity>
</View>
</View>
</TopModal>
)
}
}
function Title({ title }) {
return <Text style={g(styles, 'form-label')}>{title}</Text>
}
function FormInput({ item, value, onChange }) {
return (
<View style={g(styles, 'form-item')}>
<Title title={item.label} />
<TextInput
placeholder="请输入"
onChangeText={text => onChange(item.field, text)}
style={g(styles, 'form-item__input')}
defaultValue={value}
/>
</View>
)
}
/**
* @description:
* @param {*} item
* @param {*} value
* @return {*}
*/
function FormRadio({ item, value, onChange }) {
return (
<View style={g(styles, 'form-item')}>
<Title title={item.label} />
<View style={g(styles, 'form-item__radio')}>
{item.options.map(option => {
return (
<TouchableOpacity
key={option.value}
activeOpacity={0.8}
style={g(styles, {
'form-item__radio-item': true,
'form-item__radio-active': R.includes(option.value, value || []),
})}
onPress={() => {
let values = R.clone(value || [])
if (R.includes(option.value, values)) {
values = R.compose(R.remove(R.__, 1, values), R.findIndex(R.equals(option.value)))(values)
} else {
values = R.append(option.value, values)
}
onChange(item.field, values)
}}
>
<Text
style={g(styles, {
'form-item__radio-text': true,
'form-item__radio-text-active': R.includes(option.value, value || []),
})}
>
{option.label}
</Text>
</TouchableOpacity>
)
})}
</View>
</View>
)
}
@import '../../assets/styles/base.styl'
@import '../../assets/styles/variable.styl'
.container
flex 1
background-color home_background_color
/*
* @FilePath: /BoneHouse_Hospital_APP/src/pages/order/consumable.tsx
* @Author: peii
* @Date: 2021-06-06 13:12:28
* @LastEditTime: 2021-12-06 15:02:35
* @LastEditors: peii
* @Vision: 1.0
* @Description: 医院版耗材下单(北京华鸿)
*/
// @ts-nocheck
import React, { Component } from 'react'
import { View, SafeAreaView } from 'react-native'
import { IPlan, IFormField } from 'bonehouse'
import { INavigation } from 'navigation'
import { connect } from 'react-redux'
import * as R from 'ramda'
import dayjs from 'dayjs'
import Resolution from '../../components/common/Resolution'
import Form from '../../components/form'
import { FieldType, SelectMode } from '../../enums'
import Header from '../../components/header/header'
import { g, getFormItem, isBlank, show, isNotBlank } from '../../utils/utils'
import LocalVariable from '../../../app/containers/common/LocalVariable'
import { getUrlParams } from '../../../app/utils/Utils'
import { GetRequest, PostRequest } from '../../../app/network/RequestUtils'
import { reqOrgDepartments, reqSelfSurgeryHospital } from '../../../app/action/SelfAction'
import styles from './consumable.styl'
type IProps = {
navigation: INavigation
formItems: any[]
valueSets: any[]
userInfo: any
host: string
setSelfInitData: Function
}
type IState = {
formItems: IFormField[]
}
class SelfOrder extends Component<IProps, IState> {
state: IState = {
authorizations: [],
productAuthorization: 'N',
data: {
org_code: this.props.userInfo.department_code,
seller_code: this.props.userInfo.user_name,
take_cert_flag: 'Y',
replace_item_flag: 'N',
Caller: 'dingding',
},
formItems: [
{
field: 'department_code',
label: '业务科室',
type: 'SELECT',
order: 10,
rules: [{ required: true, message: '请选择临床科室' }],
options: [],
},
{
field: 'seller_code',
label: '下单人',
type: 'SELECT',
order: 11,
disabled: true,
rules: [{ required: true }],
options: [
{
label: this.props.userInfo.person_name,
value: this.props.userInfo.user_name,
},
],
},
{
field: 'pur_manufacturer',
label: '生产厂家',
type: FieldType.SELECT,
placeholder: '请选择',
options: [],
optionsCode: 'PUR_MANUFACTURER',
order: 41,
multiline: true,
},
{
field: 'lines',
label: '选择产品',
type: FieldType.SELECT,
selectMode: SelectMode.PAGE,
placeholder: '请选择',
options: [],
rules: [{ required: true, message: '请选择产品' }],
// refrence: ['source_id'],
customHandler: this.linesBeforeHandler.bind(this),
order: 50,
},
{
field: 'remark',
label: '备注',
type: FieldType.TEXT,
multiline: true,
order: 60,
},
],
}
constructor(props) {
super(props)
this.setData = this.setData.bind(this)
this.submitHandler = this.submitHandler.bind(this)
}
componentWillUnmount() {
this.props.setSelfInitData()
}
componentDidMount() {
this.setFormItems()
this.getDepartments()
this.getCustomer()
setTimeout(() => {
this.setOptions()
}, 0)
}
/**
* @description: 设置修改值
* @param {*}
* @return {*}
*/
setData(key: string, value: any) {
return new Promise<any>((resolve, reject) => {
const { data, formItems } = this.state
data[key] = value
console.log(data)
this.setState({ data }, () => {
const item = getFormItem(formItems, key)
if (item && item.callback) {
if (R.type(item.callback) === 'Function') {
item.callback.call(this)
} else if (R.type(item.callback) === 'String' && R.type(this[item.callback]) === 'Function') {
this[item.callback].call(this)
}
}
resolve()
})
})
}
/**
* @description: 设置正确的formItems
* @param {*}
* @return {*}
* @deprecated
*/
setOptionalFormItems() {
let formItems = R.pathOr([], ['formItems', 'MOBILE_SELF_HELP_ORDER_HOSPITAL_FORM_ITEMS'])(this.props)
formItems = R.compose(
R.pluck('formItem'),
R.filter(isNotBlank),
R.map(item => {
try {
let valueDesc = JSON.parse(item.value_desc)
valueDesc.field = item.value_code
valueDesc.label = item.value_name
item.formItem = valueDesc
return item
} catch (error) {
return null
}
}),
R.filter(R.allPass([R.propEq('value_tag', 'Y'), R.compose(isNotBlank, R.prop('value_desc'))])),
)(formItems)
this.setState({ formItems })
}
/**
* @description: 设置部分FormItem
* @param {*}
* @return {*}
*/
async setFormItems() {
let { data, formItems } = this.state
const type = this.props.navigation.getParam('type', 'HOSPITAL_COLLECT')
data.order_type_code = type
this.setState({ data })
if (type === 'SURGERY_ORDER') {
const items = [
{
field: 'source_id',
label: '手术规划',
options: [],
order: 20,
type: FieldType.SELECT,
selectMode: SelectMode.PAGE,
customHandler: this.selectPlaneHandler.bind(this),
rules: [],
},
{
field: 'patient_name',
label: '病人姓名',
type: FieldType.TEXT,
order: 21,
},
{
field: 'surgery_date',
label: '手术时间',
type: FieldType.DATE,
dateMode: 'datetime',
placeholder: '请选择',
rules: [],
order: 30,
},
{
field: 'surgery_type',
label: '手术类型',
type: FieldType.SELECT,
placeholder: '请选择',
options: [],
optionsCode: 'ORTHOPEDICS_PRODUCT_CLASS',
order: 40,
},
]
formItems = R.compose(R.sort(R.ascend(R.prop('order'))), R.concat(items))(formItems)
this.setState({ formItems })
}
// const doctorCode = 'BusinessPersonnel'
// const isDoctor = R.compose(R.includes(doctorCode), R.pluck('role_code'), R.propOr([], 'user_roles'))(userInfo)
// const options = R.compose(
// R.map(
// R.applySpec({
// value: R.prop('value_code'),
// label: R.prop('value_name'),
// }),
// ),
// R.propOr([], 'SUR_ORDER_TYPE'),
// )(valueSets)
// 如果是医生,不显示订单类型
// if (isDoctor) {
// const { data } = this.state
// TODO: 医生时hardcode为 手术下单,这个order_type_code未定
// data.order_type_code = 'HOSPITAL_COLLECT'
// } else {
// const item = {
// field: 'order_type_code',
// label: '订单类型',
// type: FieldType.SELECT,
// options,
// rules: [{ required: true }],
// order: 12,
// }
// let { formItems } = this.state
// formItems = R.compose(R.sort(R.ascend(R.prop('order'))), R.append(item))(formItems)
// this.setState({ formItems })
// }
}
/**
* TODO: 这个接口商业版有,医院版没有,用原来的value_set_code集值
* @description: 获取自助下单订单类型
* @param {*}
* @return {*}
*/
async getOrderType() {
try {
const { host, userInfo, token } = this.props
const params = {
access_token: token,
value_set_code: 'SUR_ORDER_TYPE',
org_code: userInfo.department_code,
order_type: 'SUR_ORDER_TYPE',
}
const res = await GetRequest(host, getUrlParams('/system/order_type/search', params))
console.log(res)
} catch (error) {}
}
/**
* @description: 通过 valueSet设置的formItem options
* @param {*}
* @return {*}
*/
setOptions() {
const { formItems } = this.state
R.compose(
R.map(item => {
item.options = R.compose(
R.map(
R.applySpec({
label: R.prop('value_name'),
value: R.prop('value_code'),
}),
),
R.pathOr([], ['valueSets', item.optionsCode]),
)(this.props)
}),
R.filter(R.compose(isNotBlank, R.prop('optionsCode'))),
)(formItems)
this.setState({ formItems })
}
/**
* @description: 获取部门
* @param {*}
* @return {*}
*/
async getDepartments() {
try {
const { token, host, userInfo } = this.props
const params = {
access_token: token,
org_code: userInfo.department_code,
seller_code: userInfo.user_name,
scope_flag: 'Y',
}
const res = await reqOrgDepartments(host, params)
console.log(res)
if (res.error_code !== 0) return show(res.error_msg || '请求异常,请重试')
const options = R.compose(
R.map(
R.applySpec({
value: R.prop('department_code'),
label: R.prop('department_name'),
}),
),
R.pathOr([], ['data', 'relationships']),
)(res)
const { formItems } = this.state
const item: IFormField = R.find(R.propEq('field', 'department_code'))(formItems)
if (isBlank(item)) return
item.options = options
this.setState({ formItems })
} catch (error) {
console.log(error)
}
}
/**
* @description: 获取客户信息
* @param {*}
* @return {*}
*/
async getCustomer() {
try {
const { token, host, userInfo } = this.props
const params = {
access_token: token,
org_code: userInfo.department_code,
seller_code: userInfo.user_name,
}
const res = await reqSelfSurgeryHospital(host, params)
if (res.error_code !== 0) {
throw new Error(res.error_msg)
}
console.log(res)
if (isBlank(res.data.customers)) {
return show('没有设置默认客户信息,请联系管理员设置客户信息')
}
const customer = R.path(['data', 'customers', 0])(res)
const bill_to_site = R.path(['bill_to_sites', 0])(customer)
if (isBlank(bill_to_site)) {
return show('没有设置默认客户信息,请联系管理员设置客户信息')
}
const ship_to_site = R.path(['ship_to_sites', 0])(bill_to_site)
if (isBlank(ship_to_site)) {
return show('没有设置默认客户信息,请联系管理员设置客户信息')
}
const productAuthorization = R.pathOr('N', ['sal_seller_customer_product_authorization'])(ship_to_site)
let authorizations = []
if (productAuthorization === 'Y') {
const auths = R.compose(R.unnest, R.pluck('authorization'), R.propOr([], 'ship_to_sites'))(bill_to_site)
const suppliers = R.groupBy(R.prop('supplier_code'))(auths)
authorizations = R.compose(
R.map(key => {
const values = suppliers[key]
return {
product_line_category_list: R.compose(
R.uniqBy(R.prop('product_line_category_code')),
R.unnest,
R.pluck('product_line_category_list'),
)(values),
supplier_code: R.pathOr('', [0, 'supplier_code'])(values),
supplier_name: R.pathOr('', [0, 'supplier_name'])(values),
}
}),
R.keys,
R.clone,
)(suppliers)
}
const tmpData = {
customer_code: customer.customer_code,
bill_to_site_code: bill_to_site.bill_to_site_code,
ship_to_site_code: ship_to_site.ship_to_site_code,
}
let { data } = this.state
data = {
...data,
...tmpData,
}
this.setState({
data,
authorizations,
productAuthorization,
})
} catch (error) {
show(error.message || '请求失败,请重试')
}
}
/**
* @description: 选择手术规划
* @param {*}
* @return {*}
*/
selectPlaneHandler() {
let { data, formItems } = this.state
this.props.navigation.navigate('HospitalSurgeryPlan', {
sourceId: data.source_id,
callback: plan => {
const surgeryDate = plan.surgeryDate && dayjs(plan.surgeryDate).set('h', 10).format('YYYY-MM-DD HH:mm')
const selectedData = {
source_id: plan.id,
source_number: plan.surgeryId,
doctor_name: plan.doctorName,
surgery_date: surgeryDate,
surgery_name: plan.surgeryName,
patient_name: plan.patientName,
}
data = Object.assign({}, data, selectedData)
const item: IFormField = R.find(R.propEq('field', 'source_id'))(formItems)
item.options = [
{
value: plan.id,
label: plan.surgeryName + ' ' + plan.doctorName,
},
]
this.setState({ data, formItems }, () => {
this.formRef.checkCanSubmit()
})
},
})
}
/**
* @description: 选择产品
* @param {*}
* @return {*}
*/
linesBeforeHandler() {
const { data, authorizations, productAuthorization } = this.state
this.props.navigation.navigate('ChooseProductPage', {
title: '选择产品',
selfData: {
org_code: this.props.userInfo.department_code,
filter_manufacturer_code: isBlank(data.pur_manufacturer) ? [] : R.split(',', data.pur_manufacturer),
filter_surgery_type: data.surgery_type,
authorizations,
productAuthorization
},
productCallBack: items => {
const { data, formItems } = this.state
const option = {
value: 'lineTmp',
label: '',
}
items &&
items.map(item => {
if (!!item.selectedQuantity) {
option.label += `【${item.supplier_short_name}】`
}
})
const item = R.find(R.propEq('field', 'lines'))(formItems)
if (isBlank(option.label)) {
data.lines = ''
data.linesData = []
item.options = []
} else {
data.lines = option.value
data.linesData = R.clone(items)
item.options = [option]
}
this.setState({ data, formItems }, () => {
this.formRef.checkCanSubmit()
})
},
})
}
/**
* @description: 获取产品
* @param {*}
* @return {*}
*/
getSubLines() {
let { data } = this.state
// 修改提交的行数据
let local_lines = R.clone(data.linesData)
let res_lines = []
let showPackageTip = false
local_lines.forEach(sup_item => {
if (
sup_item[LocalVariable.SELECTED_QUQNTITY] > 0 &&
sup_item.leftOptionList &&
sup_item.leftOptionList.length > 0
) {
sup_item.leftOptionList.map(lef_item => {
// let select_arr = lef_item[LocalVariable.SELECTED_DATA_ARR]
let select_arr = lef_item.selectedArr || []
if (lef_item[LocalVariable.SELECTED_QUQNTITY] > 0 && select_arr && select_arr.length > 0) {
if (lef_item.category_code === LocalVariable.SURGICAL_TEMPLATE) {
// 手术套包
select_arr.forEach(sel_item => {
let template_number = sel_item.template_number
if (
sel_item[LocalVariable.CHILDREN_LINE_NAME] &&
sel_item[LocalVariable.CHILDREN_LINE_NAME].length > 0
) {
sel_item[LocalVariable.CHILDREN_LINE_NAME].forEach(chi_item => {
if (chi_item[LocalVariable.LINE_OPTIONS] && chi_item[LocalVariable.LINE_OPTIONS].length > 0) {
chi_item[LocalVariable.LINE_OPTIONS].forEach(lin_item => {
if (
lin_item[LocalVariable.SELECTED_DATA_ARR] &&
lin_item[LocalVariable.SELECTED_DATA_ARR].length > 0
) {
lin_item[LocalVariable.SELECTED_DATA_ARR].forEach(sel_item => {
if (sel_item[LocalVariable.QUANTITY_FIELD] > 0) {
// sel_item['template_number'] = template_number // 暂时不用
sel_item[LocalVariable.PLAN_QUANTITY] = sel_item[LocalVariable.QUANTITY_FIELD]
res_lines.push(sel_item)
}
})
}
})
}
})
}
})
} else if (
lef_item.category_code === LocalVariable.NAIL_BOX ||
lef_item.category_code === LocalVariable.EQUIPMENT_BAG
) {
// 钉盒/器械包
if (lef_item.category_code === LocalVariable.EQUIPMENT_BAG) {
showPackageTip = true
}
select_arr.forEach(sel_item => {
if (sel_item[LocalVariable.QUANTITY_FIELD] > 0) {
// sel_item['prefer_serial_number'] = sel_item.serial_number // 暂时不用
sel_item['line_remark'] = sel_item.serial_number
sel_item[LocalVariable.PLAN_QUANTITY] = sel_item[LocalVariable.QUANTITY_FIELD]
res_lines.push(sel_item)
}
})
} else if (lef_item.category_code === LocalVariable.SCATTERED_EQUIPMENT) {
// 零散器械
select_arr.forEach(sel_item => {
if (sel_item[LocalVariable.QUANTITY_FIELD] > 0) {
sel_item[LocalVariable.PLAN_QUANTITY] = sel_item[LocalVariable.QUANTITY_FIELD]
res_lines.push(sel_item)
}
})
} else {
// 耗材
if (select_arr[0].details && select_arr[0].details.length > 0) {
// 大-中-小类
select_arr.forEach(sel_item => {
sel_item.details.forEach(end_item => {
if (end_item[LocalVariable.QUANTITY_FIELD] > 0) {
end_item[LocalVariable.PLAN_QUANTITY] = end_item[LocalVariable.QUANTITY_FIELD]
res_lines.push(end_item)
}
})
})
} else {
// 大类-小类
select_arr.forEach(sel_item => {
if (sel_item[LocalVariable.QUANTITY_FIELD] > 0) {
sel_item[LocalVariable.PLAN_QUANTITY] = sel_item[LocalVariable.QUANTITY_FIELD]
res_lines.push(sel_item)
}
})
}
}
}
})
}
})
let line_obj = {}
let end_lines = []
// 汇总同类物料
res_lines.map(line_it => {
if (!line_obj[line_it.item_code]) {
line_obj[line_it.item_code] = line_it.item_code
end_lines.push(line_it)
} else {
end_lines.forEach(function (fil_li) {
if (fil_li.item_code === line_it.item_code) {
if (line_it['line_remark']) {
fil_li.line_remark = line_it.line_remark
}
fil_li[LocalVariable.QUANTITY_FIELD] += line_it[LocalVariable.QUANTITY_FIELD]
fil_li[LocalVariable.PLAN_QUANTITY] = fil_li[LocalVariable.QUANTITY_FIELD]
}
})
}
})
end_lines.map(function (line_obj, line_ind) {
line_obj['line_number'] = line_ind + 1
})
return end_lines
}
/**
* @description: 提交下单数据
* @param {*}
* @return {*}
*/
async submitHandler() {
const { data } = this.state
if (R.any(isBlank, [data.customer_code, data.bill_to_site_code, data.ship_to_site_code])) {
return show('没有设置默认客户信息,请联系管理员设置客户信息')
}
const params = R.clone(data)
params.lines = this.getSubLines()
delete params.linesData
const host = this.props.host
const access_token = this.props.token
console.log(params)
try {
let res = await PostRequest(
host,
getUrlParams('/surgery/collect_order/via_data/create', {
access_token,
}),
{ data: params },
)
if (res.error_code === 0) {
// 打开下单成功页面
this.props.setSelfInitData()
const title = this.props.navigation.getParam('title')
this.props.navigation.navigate('SubSuccPage', {
title: `${title} - 下单成功`,
orderNumber: res.data.survey_collect_number,
})
} else {
show(res.error_msg || '请求异常,请重试')
}
} catch (error) {
console.log(error)
show(error.error_msg || '请求异常,请重试')
}
}
render() {
const title = this.props.navigation.getParam('title', '骨科智慧仓')
const { data, formItems } = this.state
return (
<View style={g(styles, 'container')}>
<Resolution.FixWidthView>
<Header
title={title}
backCallback={() => {
this.props.navigation.goBack()
}}
/>
<Form
fields={formItems}
data={data}
onChange={this.setData}
ref={ref => (this.formRef = ref)}
submitHandler={this.submitHandler}
/>
</Resolution.FixWidthView>
</View>
)
}
}
const mapStateToProps = state => ({
formItems: state.login.formItems,
valueSets: state.login.valueSets,
userInfo: state.login.userInfo,
host: state.login.global_domain_config,
token: state.login.token,
})
const mapDispatchToProps = dispatch => {
return {
setSelfInitData() {
dispatch({
type: 'SELF_INIT_DATA',
})
},
}
}
export default connect(mapStateToProps, mapDispatchToProps)(SelfOrder)
@import '../../assets/styles/base.styl'
@import '../../assets/styles/variable.styl'
.container
background-color home_background_color
flex 1
.body
flex 1
.filter
// 安卓加了这个就不能点了
&-ios
z-index 99
&-bar
@extend .row
@extend .center
height 40px
padding 0 20px
background-color home_background_color
border-bottom-width 1px
border-bottom-color #ddd
&__text
font-size 14px
color second_text_color
&__icon
width 16px
height @width
margin-left 8px
.plan-list
padding 20px
width 100%
.item
@extend .row
background-color #fff
padding 15px
margin-bottom 20px
@extend .center
&-left
width 40px
&-middle
flex 1
&-right
width 100px
&-text
font-family font_family_regular
font-size 14px
color second_text_color
padding-bottom 5px
&-name
font-size 18px
font-family font_family_semibold
&__remark
font-size 12px
padding-bottom 0
&-status
font-size 18px
color second_text_color
&__active
color primary_color
&-selected
width 18px
height 18px
&__icon
width 18px
height @width
// @ts-nocheck
import React, { Component } from 'react'
import { View, Text, FlatList, Image, TouchableOpacity, Platform } from 'react-native'
import { IPlan } from 'bonehouse'
import { INavigation } from 'navigation'
import { connect } from 'react-redux'
import * as R from 'ramda'
import { GetRequest } from '../../../app/network/RequestUtils'
import { getUrlParams } from '../../../app/utils/Utils'
import LoadingModel from '../../../app/containers/common/listDataComponent/LoadingModel'
import Resolution from '../../components/common/Resolution'
import Header from '../../components/header/header'
import { g, isBlank, isNotBlank, show, getHeaderHeight } from '../../utils/utils'
import FilterModal from './components/plan_filter_modal'
import dayjs from 'dayjs'
import styles from './plan.styl'
export const gender = R.cond([
[R.equals('1'), R.always('男')],
[R.equals('2'), R.always('女')],
[R.T, R.always('未知')],
])
export const status = R.cond([
[R.equals('REFERENCED'), R.always('已引用')],
[R.T, R.always('未引用')],
])
type IProps = {
token: string
userInfo: any
global_domain_config: string
navigation: INavigation
}
type IState = {
modalVisible: boolean
data: IPlan[]
originData: IPlan[]
}
class SurgeryPlan extends Component<IProps, IState> {
state = {
loading: false,
modalVisible: false,
data: [],
originData: [],
}
constructor(props) {
super(props)
this.onClose = this.onClose.bind(this)
this.selectHandler = this.selectHandler.bind(this)
this.filterHandler = this.filterHandler.bind(this)
}
componentDidMount() {
this.getData()
}
/**
* @description: 获取手术规划
* @param {*}
* @return {*}
*/
async getData() {
try {
const params = {
access_token: this.props.token,
status: 'UNREFERENCED'
}
this.loadingRef.show()
const res = await GetRequest(this.props.global_domain_config, getUrlParams(`/surgery/sur_plan/search`, params))
console.log(res)
this.loadingRef.hide()
if (res.error_code !== 0) return
const originData = R.compose(R.clone, R.pathOr([], ['data', 'sur_plans']))(res)
this.setState({ originData }, () => {
const filterData = this.filterModal.getData()
this.filterHandler(filterData)
})
} catch (error) {
this.loadingRef.hide()
console.log(error)
show('请求失败')
}
}
/**
* @description: 选择操作
* @param {*} item
* @return {*}
*/
selectHandler(item) {
const { goBack, state } = this.props.navigation
state.params.callback && state.params.callback(item)
goBack()
}
onClose() {
this.setState({ modalVisible: false })
}
/**
* @description: 过滤
* @param filterData
*/
filterHandler(filterData) {
const { originData } = this.state
let data = R.clone(originData)
R.compose(
R.map(key => {
const filter = filterData[key]
if (isBlank(filter)) return
if (R.type(filter) === 'Array') {
data = R.filter(R.compose(R.includes(R.__, filter), R.prop(key)))(data)
} else if (R.type(filter) === 'String') {
const regExp = new RegExp(filter, 'g')
data = R.filter(R.compose(R.test(regExp), R.prop(key)))(data)
}
}),
R.keys,
)(filterData)
this.setState({ data })
}
renderItem({ item }) {
const sourceId = this.props.navigation.getParam('sourceId', '')
return (
<TouchableOpacity
style={g(styles, 'item')}
activeOpacity={0.8}
onPress={() => {
this.selectHandler(item)
}}
>
<View style={g(styles, 'item-left')}>
<View style={g(styles, 'item-selected')}>
{R.equals(sourceId, item.id) ? (
<Image
style={g(styles, 'item-selected__icon')}
source={require('../../assets/images/radio_yes.png')}
></Image>
) : (
<Image
style={g(styles, 'item-selected__icon')}
source={require('../../assets/images/radio_no.png')}
></Image>
)}
</View>
</View>
<View style={g(styles, 'item-middle')}>
<Text style={g(styles, 'item-text', 'item-name')}>{item.surgeryName || '暂无手术名称'}</Text>
<Text style={g(styles, 'item-text', 'item-name__surgery')}>病人姓名:{item.patientName}</Text>
<Text style={g(styles, 'item-text', 'item-name__surgery')}>手术医生:{item.doctorName || '暂无'}</Text>
<Text style={g(styles, 'item-text', 'item-name__time')}>
手术时间: {(item.surgeryDate && dayjs(item.surgeryDate).format('YYYY-MM-DD')) || '暂无'}
</Text>
</View>
{/* <Text
style={g(styles, {
'item-status': true,
'item-status__active': item.status === 'REFERENCED',
})}
>
{status(item.status)}
</Text> */}
</TouchableOpacity>
)
}
render() {
const { modalVisible, data } = this.state
return (
<View style={g(styles, 'container')}>
<Resolution.FixWidthView>
<Header
title="手术规划"
backCallback={() => {
this.props.navigation.goBack()
}}
/>
<View style={[g(styles, 'body')]}>
<View style={g(styles, { filter: true, 'filter-ios': Platform.OS === 'ios' })}>
<TouchableOpacity
style={g(styles, 'filter-bar')}
activeOpacity={0.8}
onPress={() => {
this.setState({ modalVisible: !modalVisible })
}}
>
<Text style={g(styles, 'filter-bar__text')}>筛选</Text>
<Image
style={g(styles, 'filter-bar__icon')}
source={require('../../assets/images/arr_bom.png')}
></Image>
</TouchableOpacity>
{/* 过滤弹窗 */}
<FilterModal
visible={modalVisible}
onClose={this.onClose}
filterHandler={this.filterHandler}
ref={ref => (this.filterModal = ref)}
/>
</View>
<FlatList
style={g(styles, 'plan-list')}
data={data}
renderItem={this.renderItem.bind(this)}
keyExtractor={item => item.id}
></FlatList>
</View>
<LoadingModel ref={ref => (this.loadingRef = ref)} />
</Resolution.FixWidthView>
</View>
)
}
}
const mapStateToProps = state => {
return {
userInfo: state.login.userInfo,
token: state.login.token,
global_domain_config: state.login.global_domain_config,
}
}
const mapDispatchToProps = dispatch => {
return {}
}
export default connect(mapStateToProps, mapDispatchToProps)(SurgeryPlan)
@import '../../assets/styles/base.styl'
@import '../../assets/styles/variable.styl'
/*
* @FilePath: /BoneHouse_Hospital_APP/src/pages/order/quick.tsx
* @Author: peii
* @Date: 2021-05-30 14:38:19
* @Vision: 1.0
* @Description: 快速下单页面
*
* @Revision:
*
*/
import React, { Component } from 'react'
import { View, Text, ScrollView } from 'react-native'
import { inject, observer } from 'mobx-react'
import { toJS } from 'mobx'
import { IOrganization, ISurgeryCollectHeader, IFee } from 'bonehouse'
import * as R from 'ramda'
import Form from '../../components/form'
import { FieldType } from '../../enums'
import Header from '../../components/header/header'
import { g, getFormItem, isBlank, isNotBlank, show, translateSysprofile } from '../../utils/utils'
import styles from './quick.styl'
type IProps = {
sysStore: {
sysProfiles: {
// APP下单是否显示部门权限
OBS_MOBILE_DEPARTMENT_DISPLAY: string
// APP下单是否显示业务经理权限
OBS_MOBILE_BM_DISPLAY: string
// APP下单是否显示跟台员权限
OBS_MOBILE_SUR_FOLLOWER_DISPLAY: string
// APP下单是否显示送货员权限
OBS_MOBILE_DELIVERYMAN_DISPLAY: string
}
}
userStore: {
userName: string
personName: string
}
orgStore: {
organizations: IOrganization[]
orgs: Function
getCustomers: Function
customers: Function
getDepartmentsBySellerAndOrg: Function
departments: Function
followers: Function
}
}
class QuickOrder extends Component<IProps> {
constructor(props) {
super(props)
this.setData = this.setData.bind(this)
this.submitHandler = this.submitHandler.bind(this)
}
state = {
data: {
sellerCode: this.props.userStore.userName,
Caller: 'dingding',
},
formItems: [
{
field: 'sellerCode',
label: '销售员',
type: FieldType.SELECT,
options: [
{
label: this.props.userStore.personName,
value: this.props.userStore.userName,
},
],
placeholder: '请选择',
rules: [{ required: true, message: '请选择销售员' }],
disabled: true,
},
{
field: 'orgCode',
label: '组织',
type: FieldType.SELECT,
options: this.props.orgStore.orgs(),
placeholder: '请选择',
rules: [{ required: true, message: '请选择组织' }],
callback: this.setOrgCallback.bind(this),
},
{
field: 'customerCode',
label: '客户',
type: FieldType.SELECT,
options: [],
placeholder: '请选择',
rules: [{ required: true, message: '请选择客户' }],
refrence: ['orgCode'],
callback: this.setCustomerCallback.bind(this),
},
{
field: 'billToSiteCode',
label: '收单地点',
type: FieldType.SELECT,
options: [],
placeholder: '请选择',
rules: [{ required: true, message: '请选择收单地点' }],
refrence: ['orgCode', 'customerCode'],
callback: this.setCustomerCallback.bind(this),
},
{
field: 'shipToSiteCode',
label: '收货地点',
type: FieldType.SELECT,
options: [],
placeholder: '请选择',
rules: [{ required: true, message: '请选择收货地点' }],
refrence: ['orgCode', 'customerCode'],
// callback: this.setCustomerCallback.bind(this),
},
{
field: 'doctorName',
label: '主治医生',
type: FieldType.SELECT,
options: [],
placeholder: '请选择',
rules: [{ required: true, message: '请选择主治医生' }],
refrence: ['orgCode', 'customerCode'],
// callback: this.setCustomerCallback.bind(this),
},
{
field: 'surgeryTypeName',
label: '手术类型',
type: FieldType.SELECT,
options: [],
placeholder: '请选择',
rules: [],
refrence: ['orgCode', 'customerCode'],
// callback: this.setCustomerCallback.bind(this),
},
{
field: 'templateCollectNumber',
label: '手术模板',
type: FieldType.SELECT,
options: [],
placeholder: '请选择',
rules: [{ required: true, message: '请选择手术模板' }],
refrence: ['orgCode', 'customerCode'],
},
{
field: 'surgeryDate',
label: '手术时间',
type: FieldType.DATE,
dateMode: 'datetime',
placeholder: '请选择',
rules: [{ required: true, message: '请选择手术时间' }],
refrence: ['orgCode'],
},
{
field: 'orderTypeCode',
label: '订单类型',
type: FieldType.SELECT,
placeholder: '请选择',
rules: [{ required: true, message: '请选择订单类型' }],
refrence: ['orgCode'],
},
{
field: 'surgeryDesc',
label: '备注',
type: FieldType.TEXT,
placeholder: '请输入备注',
multiline: true,
rules: [],
},
{
field: 'voiceUrl',
label: '录音',
type: FieldType.VOICE,
placeholder: '还有什么要安排的,可录音备注哟!',
},
],
}
componentDidMount() {
this.setOptionsFormItems()
}
/**
* @description: 设置配置性的表单字段
*/
setOptionsFormItems() {
const { sysProfiles } = this.props.sysStore
let { formItems } = this.state
// 部门(00)第一位显示、第二位必需
let dep = translateSysprofile(sysProfiles.OBS_MOBILE_DEPARTMENT_DISPLAY)
if (dep.show) {
formItems = R.insert(
2,
{
field: 'departmentCode',
label: '部门',
type: FieldType.SELECT,
placeholder: '请选择',
options: [],
rules: [{ required: dep.required, message: '请选择客户' }],
refrence: ['orgCode'],
},
formItems,
)
}
// 业务经理(00)第一位显示、第二位必需
let businessManager = translateSysprofile(sysProfiles.OBS_MOBILE_DEPARTMENT_DISPLAY)
if (businessManager.show) {
}
// 跟台员(00)第一位显示、第二位必需
let follower = translateSysprofile(sysProfiles.OBS_MOBILE_SUR_FOLLOWER_DISPLAY)
if (follower.show) {
}
// 送货员(00)第一位显示、第二位必需
let deliver = translateSysprofile(sysProfiles.OBS_MOBILE_DELIVERYMAN_DISPLAY)
if (deliver.show) {
}
this.setState({ formItems })
}
/**
* @description: 设置修改值
* @param {*} key
* @param {*} vlaue
* @return {*}
*/
setData(key: string, value: any) {
return new Promise<any>((resolve, reject) => {
const { data, formItems } = this.state
data[key] = value
this.setState({ data }, () => {
const item = getFormItem(formItems, key)
item && item.callback && item.callback()
resolve()
})
})
}
setOrgCallback() {}
setCustomerCallback() {}
submitHandler() {}
render() {
const { formItems, data } = this.state
const { navigation } = this.props
const title = navigation.getParam('title', '骨科智慧仓')
return (
<View style={g(styles, 'container', 'bg-gray')}>
<Header
title={title}
backCallback={() => {
navigation.goBack()
}}
/>
{/* form表单 */}
<Form
fields={formItems}
data={data}
onChange={this.setData}
ref={ref => (this.formRef = ref)}
submitHandler={this.submitHandler}
/>
</View>
)
}
}
export default inject('sysStore', 'userStore', 'orgStore')(observer(QuickOrder))
{
"$schema": "../../../types/formitem.schema.json",
"formItems": [
{
"label": "临床科室",
"type": "SELECT",
"disabled": true,
"rules": [{ "required": true }],
"options": [
{
"value": "-1",
"label": "骨科关节"
}
]
},
{
"field": ""
}
]
}
@import '../../assets/styles/base.styl'
@import '../../assets/styles/variable.styl'
.container
flex 1
.login
&-bg
position absolute
top 0
left 0
right 0
bottom 0
&-box
flex 1
justify-content center
&-title
position relative
padding-left 33px
margin-bottom 40px
padding-top 70px
&-decorator
width 30px
height 3px
background-color title_text_color
margin-top 14px
&-text
font-size 21px
font-family font_family_semibold
color title_text_color
&-card
width 348px
height 390px
border-radius 16px
background-color foundation_color
margin-bottom 50px
align-self center
padding 38px 30px
&__title
padding-bottom 23px
&-text
color primary_text_color
font-size 21px
font-family font_family_semibold
&__form-item
margin-bottom 23px
width 288px
height 45px
border-radius 100px
background-color rgba(239, 239, 239, 1)
padding-left 20px
padding-right 10px
justify-content center
&-input
font-size 14px
&__btns
margin-top 40px
&__btn
width 288px
height 45px
border-radius 100px
background btn_sub_color
@extend .middle
@extend .center
&-text
color title_text_color
font-size 21px
font-family font_family_regular
&-plain
align-items flex-end
margin-top 14px
&-text
color second_text_color
font-size 14px
&-footer
align-self center
&-version
text-align center
color home_background_color
font-size second_text_size
padding-top 5px
font-family font_family_semibold
import React, { Component } from 'react'
import {
View,
Text,
TouchableOpacity,
SafeAreaView,
ImageBackground,
Image,
TextInput,
} from 'react-native'
import { inject, observer } from 'mobx-react'
import debounce from 'lodash.debounce'
import { placehold_text_color } from '../../assets/styles/base'
import styles from './signin.styl'
import { g, isBlank, show } from '../../utils/utils'
import { MsgType } from '../../enums'
import HostModal from '../../components/modals/host/host'
type IProps = {
store: {
version: string
setHost: Function
}
userStore: {
username: string
password: string
signin: Function
}
}
/**
* 登录页面
*/
class Signin extends Component<IProps> {
state = {
username: '',
password: '',
visible: false,
loading: false,
}
constructor(props) {
super(props)
this.loginHandler = debounce(this.loginHandler.bind(this), 300)
this.updateVisible = this.updateVisible.bind(this)
}
componentDidMount() {
// 从刚开始的asyncStorage中获取东西要等一下
setTimeout(() => {
const { username, password } = this.props.userStore
this.setState({ username, password })
}, 500)
}
/**
* 登录
*/
async loginHandler() {
const { username, password, loading } = this.state
const { navigation } = this.props
if (loading) return
if (isBlank(username)) return show('请输入您的用户名')
if (isBlank(password)) return show('请输入您的密码')
await this.props.userStore.signin(username, password)
navigation.navigate('Main')
}
/**
* 打开域名弹窗
* @param visible
*/
updateVisible(visible: boolean) {
this.setState({ visible: visible })
}
render() {
const { store } = this.props
const { username, password, showPassword, visible } = this.state
return (
<View style={g(styles, 'container')}>
<SafeAreaView style={styles.container}>
<ImageBackground
resizeMode="cover"
source={require('../../../app/images/login_bg.png')}
style={g(styles, 'login-bg')}
>
<View style={g(styles, 'login-box')}>
<View style={g(styles, 'login-title')}>
<Text style={g(styles, 'login-title-text')}>骨科智慧仓</Text>
<View style={g(styles, 'login-title-decorator')}></View>
</View>
{/* 中间主逻辑部分 */}
<View style={g(styles, 'login-card')}>
<View style={g(styles, 'login-card__title')}>
<Text style={g(styles, 'login-card__title-text')}>账号登陆</Text>
</View>
<View style={g(styles, 'login-card__form-item')}>
<TextInput
autoCapitalize="none"
placeholder="请输入您的用户名"
placeholderTextColor={placehold_text_color}
returnKeyType="next"
style={g(styles, 'login-card__form-item-input')}
defaultValue={username}
clearButtonMode="while-editing"
onChangeText={text => this.setState({ username: text })}
></TextInput>
</View>
<View style={g(styles, 'login-card__form-item')}>
<TextInput
autoCapitalize="none"
placeholder="请输入您的密码"
placeholderTextColor={placehold_text_color}
returnKeyType="done"
style={g(styles, 'login-card__form-item-input')}
defaultValue={password}
secureTextEntry={!showPassword}
clearButtonMode="while-editing"
onChangeText={text => this.setState({ password: text })}
// onFocus={() => this.setState({ focuOnPw: true })}
// onBlur={() => this.setState({ focuOnPw: false })}
/>
{/* {!!password && focuOnPw && (
<TouchableWithoutFeedback
onPress={() => this.setState({ showPassword: !showPassword })}
style={styles.view_password_btn}
>
<Image
source={require('../../images/eye.png')}
style={styles.view_password}
/>
</TouchableWithoutFeedback>
)} */}
</View>
<View style={g(styles, 'login-card__btns')}>
<TouchableOpacity
style={g(styles, 'login-card__btn')}
onPress={this.loginHandler}
activeOpacity={0.8}
>
<Text style={g(styles, 'login-card__btn-text')}>登录</Text>
</TouchableOpacity>
<TouchableOpacity
style={g(styles, 'login-card__btn-plain')}
onPress={() => {
this.updateVisible(true)
}}
activeOpacity={0.8}
>
<Text style={g(styles, 'login-card__btn-plain-text')}>修改域名</Text>
</TouchableOpacity>
</View>
</View>
{/* 最后部分 */}
<View style={g(styles, 'login-footer')}>
<Image
style={g(styles, 'login-footer-image')}
source={require('../../../app/images/logo_foo.png')}
></Image>
<Text style={g(styles, 'login-footer-version')}>v{store.version}</Text>
</View>
</View>
</ImageBackground>
{/* 域名弹窗 */}
<HostModal visible={visible} updateVisible={this.updateVisible} />
</SafeAreaView>
</View>
)
}
}
export default inject('store', 'userStore')(observer(Signin))
@import '../../assets/styles/base.styl'
@import '../../assets/styles/variable.styl'
.body
flex 1
justify-content center
align-items center
.success
&-title
margin-top 10px
font-size 17px
color primary_text_color
font-family font_family_medium
&-text
margin-top 21px
font-size 14px
color second_text_color
font-family font_family_regular
.btn
width 333px
height 50px
border-radius 25px
background-color primary_color
justify-content center
align-items center
margin-top 38px
margin-bottom 100px
&-text
color btn_color
font-size 17px
font-family font_family_regular
import React, { Component } from 'react'
import { View, Text, ScrollView, Clipboard, Image, TouchableOpacity } from 'react-native'
import { IOrganization, ISurgeryCollectHeader, IFee } from 'bonehouse'
import * as R from 'ramda'
import Header from '../../components/header/header'
import { g, getFormItem, isBlank, isNotBlank, show } from '../../utils/utils'
import styles from './success.styl'
type IProps = {
navigation: any
}
export default ({ navigation }) => {
const { orderNumber, title } = navigation.state.params
return (
<View style={g(styles, 'container')}>
<Header title={title} backCallback={() => navigation.navigate('Main')} />
<View style={g(styles, 'body')}>
<Image
style={g(styles, 'success-icon')}
source={require('../../assets/images/cor_green.png')}
></Image>
<Text style={g(styles, 'success-title')}>提交成功</Text>
<Text style={g(styles, 'success-text')}>订单号:{orderNumber || '未知订单号'}</Text>
<TouchableOpacity
style={g(styles, 'btn')}
activeOpacity={0.8}
onPress={async () => {
let hide
if (orderNumber) {
Clipboard.setString(orderNumber)
await Clipboard.getString()
hide = show('复制成功')
}
setTimeout(
() => {
hide && hide()
navigation.navigate('Main')
},
hide ? 1000 : 0,
)
}}
>
<Text style={g(styles, 'btn-text')}>复制订单号并返回主页</Text>
</TouchableOpacity>
</View>
</View>
)
}
import React, { Component } from 'react'
import { View, Text, Image } from 'react-native'
import {
createAppContainer,
createStackNavigator,
createMaterialTopTabNavigator,
createSwitchNavigator,
} from 'react-navigation'
import { font_family_regular, first_text_color } from './assets/styles/base'
import Resolution from './components/common/Resolution'
import Home from './pages/index/index'
import Mine from './pages/mine/mine'
import Signin from './pages/signin/signin'
import Consume from './pages/consume/consume'
import Consumables from './pages/consume/consumables'
import ConsumeFee from './pages/consume/fee'
import QuickOrder from './pages/order/quick'
import Success from './pages/success/success'
function createNavigator() {
const options = {
navigationOptions: {
gesturesEnabled: true,
},
headerMode: 'none',
}
const TabNavigator = createMaterialTopTabNavigator(
{
Home: {
screen: Home,
navigationOptions: {
tabBarLabel: '业务',
tabBarIcon: ({ focused }) => (
<Image
source={
focused
? require('../app/images/tab_mod_sel.png')
: require('../app/images/tab_mod_def.png')
}
/>
),
},
},
Mine: {
screen: Mine,
navigationOptions: {
tabBarLabel: '我',
tabBarIcon: ({ focused }) => (
<Image
style={{ width: 20, height: 20 }}
source={
focused
? require('./assets/images/tab_mine_sel.png')
: require('./assets/images/tab_mine_def.png')
}
/>
),
},
},
},
{
tabBarPosition: 'bottom',
swipeEnabled: true,
animationEnabled: true,
tabBarOptions: {
style: {
height: 90,
backgroundColor: '#fff',
borderTopWidth: 0.5,
borderTopColor: '#ddd',
},
labelStyle: { color: first_text_color, fontFamily: font_family_regular },
showIcon: true,
indicatorStyle: {
backgroundColor: 'transparent',
},
},
},
)
const SwitchNavigator = createSwitchNavigator({
Main: { screen: TabNavigator },
Signin: { screen: Signin },
})
const stackNavigator = createStackNavigator(
{
Main: { screen: SwitchNavigator },
Consume: { screen: Consume },
Consumables: { screen: Consumables },
ConsumeFee: { screen: ConsumeFee },
QuickOrder: { screen: QuickOrder },
Success: { screen: Success },
},
{ initialRouteName: 'Main', ...options },
)
return createAppContainer(stackNavigator)
}
export default function () {
const Navigation = createNavigator()
return (
<Resolution.FixWidthView>
<Navigation />
</Resolution.FixWidthView>
)
}
/*
* @FilePath: /BoneHouse_Hospital_APP/src/services/request.ts
* @Author: peii
* @Date: 2021-04-24 22:45:15
* @Vision: 1.0
* @Description:
*
* @Revision:
*
*/
// @ts-nocheck
import * as R from 'ramda'
import { isBlank, show, genPid } from '../utils/utils'
import { stringify } from 'querystring'
import Store from '../stores/store'
import container from '../inversify'
import { TYPES } from '../inversify/types'
import { transformObject } from '../utils/transform'
interface RequestConfig {
url: string
method: string
data: any
headers: any
timeout: number
urlToken: boolean
needToken: boolean
}
let requestQueue = []
/**
* @description: 总请求
* @param {Partial} args
* @return {*}
*/
export const request = (args: Partial<RequestConfig>) => {
const store = container.get<Store>(TYPES.Store)
let cancel = null
let isCancel = false
const p = new Promise((resolve, reject) => {
cancel = () => {
isCancel = true
reject({ errorCode: 400, errorMsg: '取消' })
}
let options: any = {
headers: {
'Content-Type': 'application/json',
},
method: R.propOr('get', 'method', args),
reTries: R.propOr(3, 'reTries', args),
needToken: R.propOr(true, 'needToken', args),
data: R.propOr({}, 'data', args),
...args,
}
if (options.needToken && store.token) {
options.data.accessToken = store.token
if (options.method.toUpperCase() === 'POST') {
const token = 'access_token=' + store.token
options.url += R.ifElse(
R.includes('?'),
R.always('&' + token),
R.always('?' + token),
)(options.url)
}
}
args.data = transformObject(options.data, 'toLine')
options = R.cond([
[
R.propEq('method', 'get'),
() => R.assoc('url', args.url + '?' + stringify(args.data), options),
],
[R.T, () => R.assoc('body', JSON.stringify(args.data), options)],
])(options)
// 上传方式
if (options.headers['Content-Type'] === 'multipart/form-data') {
options.url += `?access_token=${store.token}`
options = R.assoc('body', options.data, options)
}
let requestTimes = 0
function doRequest() {
requestTimes += 1
console.log('请求URL:', store.host + options.url)
fetch(store.host + options.url, options)
.then(res => res.json())
.then(res => {
if (isCancel) return
console.log('返回结果:', res)
R.ifElse(
fetchSuccess,
() => {
removeRequestByPid(pid)
resolve(transformObject(res, 'toHump'))
},
() => {
throw res
},
)(res)
})
.catch(e => {
if (isCancel) return
// 登录错误直接cancel掉
if (e.error_code === 41006) {
show(e.error_msg)
removeRequestByPid(pid)
R.map(p => {
p.cancel()
}, requestQueue)
requestQueue = []
store.navigation.navigate('Signin')
return
}
if (requestTimes < options.reTries) {
return doRequest()
}
failHandler(e, store, pid)
})
}
doRequest()
})
const pid = genPid()
requestQueue.push({ pid, p, cancel })
return p.catch(e => {
return e
})
}
const fetchSuccess = R.propEq('error_code', 0)
const removeRequestByPid = pid => {
requestQueue = R.compose(
R.remove(R.__, 1, requestQueue),
R.findIndex(R.propEq('pid', pid)),
)(requestQueue)
}
const failHandler = async (err: any, store: Store, pid) => {
R.ifElse(
isBlank,
() => {
show(err.status ? `${err.status} ${err.statusText}` : err.message)
},
() => {
show(err.error_msg)
removeRequestByPid(pid)
},
)(err.error_code)
return err
}
/*
* @FilePath: /BoneHouse_Business_APP/src/services/service.ts
* @Author: peii
* @Date: 2021-04-24 22:45:15
* @Vision: 1.0
* @Description: 网络服务
*
*/
import { request } from './request'
import { injectable } from 'inversify'
const ctx = '/api/latest'
@injectable()
export default class Service {
/**
* 获取系统配置
*/
getSysProfile(data: any) {
return request({ url: `${ctx}/system/sys_profile/search`, data })
}
/**
* @description: 获取系统值集
* @param {object} data
* @return {*}
*/
getSysValueSet(data: { valueSetCode: string }) {
return request({ url: `${ctx}/system/value_set/search`, data })
}
/**
* 登录
* @param data
* @returns
*/
signin(data: { data: { user_name: string; user_password: string; grant_type: string } }) {
return request({
url: `${ctx}/access_token/password/search?app_code=MOBILE`,
data,
method: 'POST',
})
}
/**
* 获取组织
* @returns
*/
getOrganizations() {
return request({ url: `${ctx}/authorized_inventory/search` })
}
/**
* 获取客户
* @param data
* @returns
*/
getCustomers(data: { orgCode: string; sellerCode: string }): Promise<any> {
return request({ url: `${ctx}/sale/seller_customer/search`, data })
}
/**
* @description: 根据组织和销售员获取部门信息
* @param {object} data
* @return {*}
*/
getDepartmentsBySellerAndOrg(data: { orgCode: string; sellerCode: string; scopeFlag: string }) {
return request({ url: `${ctx}/sale/sale_relationship/search`, data })
}
/**
* @description: 获取借货订单
* @param {*}
* @return {*}
*/
getCollectOrders(data: {
orgCode: string
sellerCode?: string
departmentCode?: string
customerCode: string
collectHeaderStatus: string
}) {
return request({ url: `${ctx}/surgery/collect_order/search`, data })
}
/**
* @description: 获取借货订单行
* @param {*} data
* @return {*}
*/
getCollectOrderLines(data: { surgeryCollectNumber: string }) {
return request({ url: `${ctx}/surgery/collected_order_line/search`, data })
}
/**
* @description: 图片上传
* @param {FormData} data
* @return {*}
*/
uploadImg(data: FormData) {
return request({
url: `${ctx}/dingding/upload_media`,
headers: { 'Content-Type': 'multipart/form-data' },
method: 'POST',
data,
timeout: 300000,
urlToken: true,
needToken: false,
})
}
/**
* @description: 创建消耗订单
* @param {any} data
* @return {*}
*/
createConsumeOrder(data: any) {
return request({ url: `${ctx}/surgery/consume_order/create`, data, method: 'post' })
}
}
// @ts-nocheck
/*
* @FilePath: /BoneHouse_Business_APP/src/stores/consume.ts
* @Author: peii
* @Date: 2021-05-10 11:57:51
* @Vision: 1.0
* @Description: 消耗确认
*
* @Revision:
*
*/
import { observable, flow, action } from 'mobx'
import { ISurgeryCollectHeader, ISurgeryCollectLine } from 'bonehouse'
import { injectable, inject } from 'inversify'
import * as R from 'ramda'
import { isNotBlank } from '../utils/utils'
import Service from '../services/service'
import { TYPES } from '../inversify/types'
import dayjs from 'dayjs'
@injectable()
export default class Consume {
@inject(TYPES.Service)
service!: Service
@observable _orders: { [key: string]: ISurgeryCollectHeader[] } = {}
@observable _orderLines: { [key: string]: ISurgeryCollectLine[] } = {}
@observable loading = false
@observable selectedLines: ISurgeryCollectLine[] = []
@action.bound
resetOrders() {
this._orders = {}
}
@action.bound
resetOrderLines() {
this._orderLines = {}
}
/**
* @description: 设置用户选择的消耗行
* @return {*}
*/
@action.bound
setSelectedLines(lines: ISurgeryCollectLine) {
this.selectedLines = lines
}
/**
* @description: 借货订单列表
* @param {string} sellerCode
* @param {string} orgCode
* @param {string} customerCode
* @return {*}
*/
orders(sellerCode: string, orgCode: string, customerCode: string) {
const orders = this._orders[`${sellerCode}_${orgCode}_${customerCode}`] || []
function concat() {
return R.reduce((prev: string, next: string) => {
return prev + next + '-'
}, '')(arguments)
}
return R.map(
R.applySpec({
label: R.compose(
R.init,
R.converge(concat, [
R.prop('collectNumber'),
R.propOr('无', 'surgeryName'),
R.propOr('无', 'doctorName'),
R.compose(date => {
return date && dayjs(date).format('YYYY-MM-DD')
}, R.prop('createTime')),
]),
),
value: R.prop('collectNumber'),
}),
)(orders)
}
/**
* @description: 订单跟台员
* @param {string} surgeryCollectNumber
* @return {*}
*/
orderFollower(sellerCode, orgCode, customerCode, surgeryCollectNumber) {
const orders = this._orders[`${sellerCode}_${orgCode}_${customerCode}`] || []
const order = R.find(R.propEq('surgeryCollectNumber', surgeryCollectNumber))(orders)
if (isNotBlank(order) && isNotBlank(order.surgeryFollowerCode)) {
return { value: order.surgeryFollowerCode, label: order.surgeryFollowerName }
}
}
/**
* @description: 订单医生
* @param {*} sellerCode
* @param {*} orgCode
* @param {*} customerCode
* @param {*} surgeryCollectNumber
* @return {*}
*/
orderDoctor(sellerCode, orgCode, customerCode, surgeryCollectNumber) {
const orders = this._orders[`${sellerCode}_${orgCode}_${customerCode}`] || []
const order = R.find(R.propEq('surgeryCollectNumber', surgeryCollectNumber))(orders)
return R.propOr('', 'doctorName')(order)
}
/**
* @description:
* @param {*} orderId
* @return {*}
*/
orderLines(orderId) {
return this._orderLines[orderId]
}
/**
* @description: 获取借货订单头列表
* @param {*}
* @return {*}
*/
getOrders = flow(function* (this: Consume, params: any) {
const res = yield this.service.getCollectOrders(params) as any
const { sellerCode, orgCode, customerCode } = params
this._orders[`${sellerCode}_${orgCode}_${customerCode}`] = res.data.surgeryCollectHeaders
})
/**
* @description: 获取借货订单行列表
* @param {string} surggerCollectNumber
* @return {*}
*/
getOrderLines = flow(function* (this: Consume, surgeryCollectNumber: string) {
this.loading = true
const res = yield this.service.getCollectOrderLines({
surgeryCollectNumber,
filterNoneFlag: 'Y',
})
this.loading = false
this._orderLines[surgeryCollectNumber] = R.compose(
R.reject(R.propEq('raisedConsume', 'Y')),
R.pathOr([], ['data', 'lines']),
)(res)
})
/**
* @description: 提交数据
* @param {any} data
* @return {*}
*/
async submit(data: any) {
return await this.service.createConsumeOrder(data)
}
}
/*
* @FilePath: /BoneHouse_Business_APP/src/stores/index.ts
* @Author: peii
* @Date: 2021-04-29 16:38:54
* @Vision: 1.0
* @Description: 总仓库
*
* @Revision:
*
*/
import container from '../inversify'
import { TYPES } from '../inversify/types'
import { AsyncStorage } from 'react-native'
import { create } from 'mobx-persist'
const store = container.get<any>(TYPES.Store)
const sysStore = container.get<any>(TYPES.SysStore)
const userStore = container.get<any>(TYPES.UserStore)
const orgStore = container.get<any>(TYPES.OrgStore)
const consumeStore = container.get<any>(TYPES.Consume)
const hydrate = create({
storage: AsyncStorage,
jsonify: true,
debounce: 0,
})
hydrate('store', store)
hydrate('sysStore', sysStore)
hydrate('userStore', userStore)
hydrate('orgStore', orgStore)
export default { store, sysStore, userStore, orgStore, consumeStore }
/*
* @FilePath: /BoneHouse_Business_APP/src/stores/organization.ts
* @Author: peii
* @Date: 2021-04-29 19:30:03
* @Vision: 1.0
* @Description: 组织结构store
*
* @Revision:
*
*/
// @ts-nocheck
import { observable, action, runInAction, toJS, flow } from 'mobx'
import { persist } from 'mobx-persist'
import { injectable, inject } from 'inversify'
import Service from '../services/service'
import { IOrganization, ICustomer, IDepartment } from 'bonehouse'
import * as R from 'ramda'
import { isBlank } from '../utils/utils'
import { TYPES } from '../inversify/types'
@injectable()
export default class Organization {
@inject(TYPES.Service) service!: Service
// 组织
@persist('list') @observable organizations: IOrganization[] = []
// 库存
@persist('list') @observable inventories = []
// 客户
@observable _customers: { [key: string]: ICustomer[] } = {}
// 部门
@observable _departments: { [key: string]: IDepartment[] } = {}
orgs(): IOrganization[] {
return R.map(
R.applySpec({
label: R.prop('orgName'),
value: R.prop('orgCode'),
}) as any,
)(this.organizations as any) as any
}
/**
* 客户选项
* @param sellerCode
* @param orgCode
* @returns
*/
customers(sellerCode: string, orgCode: string): ICustomer[] {
const customers = this._customers[`${sellerCode}_${orgCode}`] || []
return R.map(
R.applySpec({
label: R.prop('customerName'),
value: R.prop('customerCode'),
}) as any,
)(customers as any) as any
}
/**
* @description: 部门选项
* @param {string} sellerCode
* @param {string} orgCode
* @return {*}
*/
departments(sellerCode: string, orgCode: string) {
const deps = this._departments[`${sellerCode}_${orgCode}`] || []
return R.map(
R.applySpec({
label: R.prop('departmentName'),
value: R.prop('departmentCode'),
}),
)(deps)
}
/**
* @description: 跟台员
* @param {string} sellerCode
* @param {string} orgCode
* @param {string} departmentCode
* @return {*}
*/
followers(sellerCode: string, orgCode: string, departmentCode: string) {
const deps = this._departments[`${sellerCode}_${orgCode}`] || []
const dep = R.find(R.propEq('departmentCode', departmentCode))(deps)
return R.compose(
R.map(
R.applySpec({
label: R.prop('surgeryFollowerName'),
value: R.prop('surgeryFollowerCode'),
}),
),
R.propOr([], 'surgeryFollowerList'),
)(dep)
}
@action
resetCustomers() {
this._customers = {}
}
/**
* @description: 获取组织
* @return {*}
*/
getOrganizations = flow(function* (this: Organization) {
const res = yield this.service.getOrganizations()
this.organizations = R.compose(
R.uniqBy(R.prop('orgCode')),
R.pathOr([], ['data', 'organizations']),
)(res)
this.inventories = res.data.inventories
})
/**
* @description: 根据组织和销售员获取客户
* @param {*} function
* @return {*}
*/
getCustomers = flow(function* (this: Organization, sellerCode: string, orgCode: string) {
const res = yield this.service.getCustomers({ orgCode, sellerCode })
this._customers[`${sellerCode}_${orgCode}`] = res.data.customers
})
/**
* @description: 根据组织和销售员获取部门
* @param {*}
* @return {*}
*/
getDepartmentsBySellerAndOrg = flow(function* (
this: Organization,
sellerCode: string,
orgCode: string,
scopeFlag = 'Y',
) {
const res = yield this.service.getDepartmentsBySellerAndOrg({ sellerCode, orgCode, scopeFlag })
this._departments[`${sellerCode}_${orgCode}`] = res.data.relationships
})
}
/*
* @FilePath: /BoneHouse_Business_APP/src/stores/store.ts
* @Author: peii
* @Date: 2021-04-24 22:45:15
* @Vision: 1.0
* @Description: 一般性store
*
* @Revision:
*
*/
import { observable, action, runInAction, toJS, flow } from 'mobx'
import { persist } from 'mobx-persist'
import { injectable, inject } from 'inversify'
import { NativeModules } from 'react-native'
import { IFunction } from 'bonehouse'
import * as R from 'ramda'
import { isBlank } from '../utils/utils'
import container from '../inversify'
import { TYPES } from '../inversify/types'
import { MOBILE_BUSINESS_MODULE } from '../constants'
@injectable()
export default class Store {
// 默认域名
@persist @observable host: string = 'https://obs.dev.xhk.guke.tech'
@persist @observable token?: string
@persist @observable version: string = '2.0.0'
// 功能模块
@persist('list') @observable functions: IFunction[] = []
@observable functionIcons = {
MOBILE_BORROW_ORDER: require('../assets/images/quick_order.png'),
MOBILE_SELF_HELP_ORDER: require('../assets/images/self_order.png'),
MOBILE_CONSUMP_CONFIRMA: require('../assets/images/equip_consu.png'),
MOBILE_DEVICE_INFORMATION: require('../assets/images/device_info.png'),
MOBILE_TRANSFER_APPLICATION: require('../assets/images/trans_order.png'),
}
@observable navigation = null
/**
* 首页功能列表
* @returns IFunction[]
*/
getBizFuns(): IFunction[] {
let funcs = toJS(this.functions)
if (isBlank(funcs)) {
return []
}
return R.compose(
R.sort(R.ascend(R.prop('functionOrder'))),
R.propOr([], 'childList'),
R.find(R.propEq('functionCode', MOBILE_BUSINESS_MODULE)),
)(funcs as any) as any
}
@action
setHost(host: string) {
this.host = host
}
@action
setToken(token: string) {
this.token = token
}
@action
setVersion(v: string) {
this.version = v
}
@action
setFunctions(functions: IFunction[]) {
this.functions = functions
}
@action
setNavigation(navigation: any) {
this.navigation = navigation
}
}
runInAction(() => {
NativeModules.RNToolsManager.getAppVersion((v: string) => {
const store = container.get<Store>(TYPES.Store)
store.setVersion(v)
})
})
/*
* @FilePath: /BoneHouse_Business_APP/src/stores/system.ts
* @Author: peii
* @Date: 2021-04-24 22:45:15
* @Vision: 1.0
* @Description: 系统store
*
* @Revision:
*
*/
import { observable, flow, runInAction, action } from 'mobx'
import { persist } from 'mobx-persist'
import { injectable, inject } from 'inversify'
import * as R from 'ramda'
import Service from '../services/service'
import { TYPES } from '../inversify/types'
import { toBinaryNumber } from '../utils/utils'
@injectable()
export default class System {
@observable
headerHeight = 78
@inject(TYPES.Service)
private service!: Service
@persist('map') @observable sysProfiles = {
// APP借货仓库显隐及是否必填
OBS_MOBILE_BOR_WARE_REQUIRED: '00',
// APP消耗是否显示部门权限
OBS_MOBILE_CONSU_DEPARTMENT_DISPLAY: '00',
// APP消耗是否显示医生权限
OBS_MOBILE_CONSU_DOCTOR_DISPLAY: '00',
// APP消耗是否显示跟台员权限
OBS_MOBILE_CONSU_FOLLOW_DISPLAY: '00',
// APP下单是否显示部门权限
OBS_MOBILE_DEPARTMENT_DISPLAY: '00',
// APP下单是否显示业务经理权限
OBS_MOBILE_BM_DISPLAY: '00',
// APP下单是否显示跟台员权限
OBS_MOBILE_SUR_FOLLOWER_DISPLAY: '00',
// APP下单是否显示送货员权限
OBS_MOBILE_DELIVERYMAN_DISPLAY: '00',
// APP器械消耗展示价格权限
OBS_MOBILE_EQU_CON_DISPLAY_PRICE: 'N',
}
@persist('map') @observable sysValueSets = {
// 消耗明细费用类型
SUR_FEE_TYPE: [],
}
@action
setHeaderHeight(height: number) {
this.headerHeight = height
}
/**
* @description: 获取系统配置
* @param {*} function
* @return {*}
*/
getSysProfile = flow(function* (this: System) {
const getProfiles = async (key: any) => {
const res = (await this.service.getSysProfile({ profileCode: key })) as any
runInAction(() => {
// @ts-ignore
this.sysProfiles[key] = isNaN(res.data.profileValue)
? res.data.profileValue
: toBinaryNumber(res.data.profileValue)
})
}
R.compose(R.map(getProfiles), R.keys)(this.sysProfiles)
})
/**
* @description: 获取系统值集
* @param {*} function
* @return {*}
*/
getSysValueSet = flow(function* (this: System) {
const getValueSets = async (key: any) => {
const res = (await this.service.getSysValueSet({ valueSetCode: key })) as any
runInAction(() => {
// @ts-ignore
this.sysValueSets[key] = res.data.sysValues
})
}
R.compose(R.map(getValueSets), R.keys)(this.sysValueSets)
})
}
/*
* @FilePath: /BoneHouse_Business_APP/src/stores/user.ts
* @Author: peii
* @Date: 2021-05-07 18:48:00
* @Vision: 1.0
* @Description: 用户仓库
*
* @Revision:
*
*/
// @ts-nocheck
import { observable, action, flow, runInAction } from 'mobx'
import { persist } from 'mobx-persist'
import { injectable, inject } from 'inversify'
import { TYPES } from '../inversify/types'
import Service from '../services/service'
import Store from './store'
import SysStore from './system'
import { IDepartment, IInventory } from 'bonehouse'
@injectable()
export default class UserStore {
@inject(TYPES.Service)
service!: Service
@inject(TYPES.Store)
store!: Store
@inject(TYPES.SysStore)
sysStore!: SysStore
// 登录信息
@persist @observable private username: string = ''
@persist @observable private password: string = ''
// 用户信息
@persist @observable private userName: string = ''
@persist @observable private personName: string = ''
@persist @observable private gender: string = ''
@persist('map') @observable private department: IDepartment = {
departmentName: '',
departmentCode: '',
}
// 用户仓库
@persist('list') @observable inventories: IInventory[] = []
@action
setUsername(username: string) {
this.username = username
}
@action
setPassword(password: string) {
this.password = password
}
/**
* 登录
*/
signin = flow(function* (this: UserStore, username, password) {
const params = {
data: {
grant_type: 'PASSWORD',
user_name: username,
user_password: password,
},
}
const res = yield this.service.signin(params)
this.username = username
this.password = password
this.department = {
departmentCode: res.departmentCode,
departmentName: res.departmentName,
}
this.inventories = res.inventorys
this.userName = res.userName
this.personName = res.personName
this.gender = res.gender
this.store.setToken(res.accessToken)
this.store.setFunctions(res.functions)
this.sysStore.getSysProfile()
this.sysStore.getSysValueSet()
})
}
import { transformObject, toHump, toLine } from './transform'
describe('Object Transform Test', () => {
test('it should be underline', () => {
expect(toLine('aBBca23DefG')).toStrictEqual('a_b_bca23_def_g')
})
})
/*
* @FilePath: /BoneHouse_Business_APP/src/utils/transform.ts
* @Author: peii
* @Date: 2021-04-24 22:45:15
* @Vision: 1.0
* @Description:
*
* @Revision:
*
*/
import * as R from 'ramda'
import { isBlank } from './utils'
/**
* 下划线转换驼峰
* @param name
*/
export function toHump(name: string) {
return name.replace(/\_(\w)/g, function (all, letter) {
return letter.toUpperCase()
})
}
/**
* 驼峰转换下划线
* @param name string
* @returns
*/
export function toLine(name: string) {
return name.replace(/([A-Z])/g, '_$1').toLowerCase()
}
export type ITransformTypes = 'toHump' | 'toLine'
export type ITransObj = { [key: string]: any } | any[]
/**
* 对象下划线和驼峰转换
* @param obj 转换对象
* @param type string 'toHump'|'toLine' 转换类型
*/
export function transformObject(obj: ITransObj, type: ITransformTypes = 'toHump') {
if (isBlank(obj)) {
return null
}
const fn = type === 'toHump' ? toHump : toLine
const transform = (item: any) => {
const desc: ITransObj = {}
R.compose(
R.map((key: string) => {
const dKey = fn.call(null, key)
if (R.type(item[key]) === 'Array' || R.type(item[key]) === 'Object') {
desc[dKey] = isBlank(item[key]) ? item[key] : transformObject(item[key], type)
} else {
desc[dKey] = item[key]
}
}),
R.keys,
)(item)
return desc
}
let des
if (R.type(obj) === 'Array') {
des = R.map(transform)(obj as any)
} else {
des = transform(obj)
}
return des
}
/*
* @FilePath: /BoneHouse_Hospital_APP/src/utils/utils.ts
* @Author: peii
* @Date: 2021-04-24 22:45:15
* @Vision: 1.0
* @Description: 工具方法
*
*/
// @ts-nocheck
import * as R from 'ramda'
import { Dimensions, Platform } from 'react-native'
import Toast from 'react-native-root-toast'
import { MsgType } from '../enums'
export const isBlank = R.anyPass([R.isNil, R.isEmpty])
export const isNotBlank = R.complement(isBlank)
/**
* 样式对象辅助函数
* @param styles 样式
* @param cls 类名
* @returns 样式对象
*/
export const getStyles = (styles: any, ...cls: any[]) => {
let clses: any = []
if (isNotBlank(styles) && isNotBlank(cls)) {
clses = R.compose(
R.concat(clses),
R.map((key: any) => {
if (R.type(key) === 'Array') {
return getStyles(styles, ...key)
}
if (R.type(key) === 'Object') {
const keys = R.compose(
R.filter(k => key[k]),
R.keys,
)(key)
return getStyles(styles, ...keys)
}
return [styles[key]]
}),
)(cls)
}
return clses
}
/**
* 样式对象辅助函数
* @param styles 样式
* @param cls 类名
* @returns 样式对象
*/
export const g = getStyles
let toast = null
/**
* 提示框
* @param {*} data 提示内容
* @param {*} type 提示类型
*/
export const show = (data: string, type = MsgType.INFO, position = Toast.positions.CENTER) => {
if (isBlank(data)) return
const types = {
[MsgType.WARN]: {
textColor: '#fa8c16',
backColor: '#fff7e6',
},
[MsgType.ERROR]: {
textColor: '#f5222d',
backColor: '#fff1f0',
},
[MsgType.SUCCESS]: {
textColor: '#52c41a',
backColor: '#f6ffed',
},
[MsgType.INFO]: {
textColor: '#fafafa',
backColor: '#222',
},
}
const colors = types[type]
if (type === MsgType.ERROR) {
data = ${data}`
} else if (type === MsgType.WARN) {
data = `! ${data}`
} else if (type == MsgType.SUCCESS) {
data = `√ ${data}`
}
if (isNotBlank(toast)) {
Toast.hide(toast)
}
toast = Toast.show(data, {
duration: Toast.durations.LONG,
position,
shadow: false,
hideOnPress: true,
delay: 0,
visible: true,
backgroundColor: colors.backColor,
textColor: colors.textColor,
shadowColor: colors.textColor,
onHidden() {
toast = null
},
})
return () => {
if (isNotBlank(toast)) {
Toast.hide(toast)
}
}
}
const X_WIDTH = 375
const X_HEIGHT = 812
const X_MAX_WIDTH = 414
const X_MAX_HEIGHT = 896
const XS_MAX_WIDTH = 428
const XS_MAX_HEIGHT = 926
const screenW = Dimensions.get('window').width
const screenH = Dimensions.get('window').height
/**
* 判断是否iPhone x,是否有刘海
* @returns boolean
*/
export const isIphoneX = (): boolean => {
return Platform.OS === 'ios' && screenH > 736
}
/**
* 生成随机ID
* @returns
*/
export const genPid = (): string => {
return new Date().getTime() + Math.random() * 1000
}
/**
* @description: 转成二进制字符串
* @param {number} n
* @return {string}
*/
export const toBinaryNumber = (n: number | string, len = 2): string => {
if (isNaN(n)) return n
let binN = parseInt(n).toString(2)
while (R.length(binN) < len) binN = '0' + binN
return binN
}
/**
* @description: form表单是否必需
* @param {Object}
* @return {Boolean}
*/
export const isRequired = R.compose(R.find(R.propEq('required', true)), R.propOr([], 'rules'))
/**
* @description: 防抖函数
* @param {Function} fn
* @param {*} wait
* @return {*}
*/
export const debounce = (fn: Function, wait = 300): Function => {
let timer = null
return function () {
const context = this
let args = arguments
clearTimeout(timer)
timer = setTimeout(() => {
fn.call(context, ...args)
}, wait)
}
}
/**
* 获取FormItem
* @param items
* @param fieldName
* @returns
*/
export const getFormItem = (items: IFormField[], fieldName: string) => R.find(R.propEq('field', fieldName), items)
/**
* @description: 解释配置性的表单项的显示及必填
* @param {string} profile
* @return {*}
*/
export const translateSysprofile = (profile: string) => {
if (isBlank(profile)) {
return { show: false, required: false }
}
const show = R.ifElse(R.pathEq([0], '1'), R.T, R.F)(profile)
const required = R.ifElse(R.pathEq([1], '1'), R.T, R.F)(profile)
return { show, required }
}
export const getHeaderHeight = () => {
const statusHeight = Platform.OS === 'android' ? 0 : isIphoneX() ? 44 : 20
return statusHeight + 58
}
/**
* @description: 性别
* @param {*}
* @return {*}
*/
export const gender = R.cond([
[R.equals('1'), R.always('男')],
[R.equals('2'), R.always('女')],
[R.T, R.always('未知')],
])
{
"compilerOptions": {
"allowJs": true,
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"isolatedModules": true,
"experimentalDecorators": true,
"jsx": "react",
"lib": ["es6"],
"moduleResolution": "node",
"noEmit": true,
"strict": true,
"target": "esnext",
"rootDir": ".",
"typeRoots": ["node_modules/@types", "types"]
},
"exclude": ["node_modules", "babel.config.js", "metro.config.js", "jest.config.js"],
"include": ["src", "types"]
}
......@@ -32,6 +32,11 @@
dependencies:
"@babel/highlight" "^7.12.13"
"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.16.0":
version "7.16.4"
resolved "https://rg.cnpmjs.org/@babel/compat-data/download/@babel/compat-data-7.16.4.tgz#081d6bbc336ec5c2435c6346b2ae1fb98b5ac68e"
integrity sha512-1o/jo7D+kC9ZjHX5v+EHrdjl3PhxMrLSOTGsOdHJ+KL8HCaEK6ehrVL2RS6oHDZp+L7xLirLrPmQtEng769J/Q==
"@babel/core@^7.0.0", "@babel/core@^7.1.0", "@babel/core@^7.4.5":
version "7.12.13"
resolved "https://registry.npm.taobao.org/@babel/core/download/@babel/core-7.12.13.tgz?cache=0&sync_timestamp=1612314799232&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fcore%2Fdownload%2F%40babel%2Fcore-7.12.13.tgz#b73a87a3a3e7d142a66248bf6ad88b9ceb093425"
......@@ -86,6 +91,16 @@
"@babel/helper-explode-assignable-expression" "^7.12.13"
"@babel/types" "^7.12.13"
"@babel/helper-compilation-targets@^7.13.0":
version "7.16.3"
resolved "https://rg.cnpmjs.org/@babel/helper-compilation-targets/download/@babel/helper-compilation-targets-7.16.3.tgz#5b480cd13f68363df6ec4dc8ac8e2da11363cbf0"
integrity sha512-vKsoSQAyBmxS35JUOOt+07cLc6Nk/2ljLIHwmq2/NM6hdioUaqEXq/S+nXvbvXbZkNDlWOymPanJGOc4CBjSJA==
dependencies:
"@babel/compat-data" "^7.16.0"
"@babel/helper-validator-option" "^7.14.5"
browserslist "^4.17.5"
semver "^6.3.0"
"@babel/helper-create-class-features-plugin@^7.12.13":
version "7.12.13"
resolved "https://registry.npm.taobao.org/@babel/helper-create-class-features-plugin/download/@babel/helper-create-class-features-plugin-7.12.13.tgz?cache=0&sync_timestamp=1612314760792&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-create-class-features-plugin%2Fdownload%2F%40babel%2Fhelper-create-class-features-plugin-7.12.13.tgz#0f1707c2eec1a4604f2a22a6fb209854ef2a399a"
......@@ -105,6 +120,20 @@
"@babel/helper-annotate-as-pure" "^7.12.13"
regexpu-core "^4.7.1"
"@babel/helper-define-polyfill-provider@^0.3.0":
version "0.3.0"
resolved "https://rg.cnpmjs.org/@babel/helper-define-polyfill-provider/download/@babel/helper-define-polyfill-provider-0.3.0.tgz#c5b10cf4b324ff840140bb07e05b8564af2ae971"
integrity sha512-7hfT8lUljl/tM3h+izTX/pO3W3frz2ok6Pk+gzys8iJqDfZrZy2pXjRTZAvG2YmfHun1X4q8/UZRLatMfqc5Tg==
dependencies:
"@babel/helper-compilation-targets" "^7.13.0"
"@babel/helper-module-imports" "^7.12.13"
"@babel/helper-plugin-utils" "^7.13.0"
"@babel/traverse" "^7.13.0"
debug "^4.1.1"
lodash.debounce "^4.0.8"
resolve "^1.14.2"
semver "^6.1.2"
"@babel/helper-explode-assignable-expression@^7.12.13":
version "7.12.13"
resolved "https://registry.npm.taobao.org/@babel/helper-explode-assignable-expression/download/@babel/helper-explode-assignable-expression-7.12.13.tgz?cache=0&sync_timestamp=1612314632461&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-explode-assignable-expression%2Fdownload%2F%40babel%2Fhelper-explode-assignable-expression-7.12.13.tgz#0e46990da9e271502f77507efa4c9918d3d8634a"
......@@ -142,6 +171,13 @@
dependencies:
"@babel/types" "^7.12.13"
"@babel/helper-module-imports@^7.16.0":
version "7.16.0"
resolved "https://rg.cnpmjs.org/@babel/helper-module-imports/download/@babel/helper-module-imports-7.16.0.tgz#90538e60b672ecf1b448f5f4f5433d37e79a3ec3"
integrity sha1-kFOOYLZy7PG0SPX09UM9N+eaPsM=
dependencies:
"@babel/types" "^7.16.0"
"@babel/helper-module-transforms@^7.12.13":
version "7.12.13"
resolved "https://registry.npm.taobao.org/@babel/helper-module-transforms/download/@babel/helper-module-transforms-7.12.13.tgz?cache=0&sync_timestamp=1612314794951&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-module-transforms%2Fdownload%2F%40babel%2Fhelper-module-transforms-7.12.13.tgz#01afb052dcad2044289b7b20beb3fa8bd0265bea"
......@@ -174,6 +210,11 @@
resolved "https://registry.npm.taobao.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.13.0.tgz#806526ce125aed03373bc416a828321e3a6a33af"
integrity sha1-gGUmzhJa7QM3O8QWqCgyHjpqM68=
"@babel/helper-plugin-utils@^7.16.5":
version "7.16.5"
resolved "https://rg.cnpmjs.org/@babel/helper-plugin-utils/download/@babel/helper-plugin-utils-7.16.5.tgz#afe37a45f39fce44a3d50a7958129ea5b1a5c074"
integrity sha512-59KHWHXxVA9K4HNF4sbHCf+eJeFe0Te/ZFGqBT4OjXhrwvA04sGfaEGsVTdsjoszq0YTP49RC9UKe5g8uN2RwQ==
"@babel/helper-remap-async-to-generator@^7.13.0":
version "7.13.0"
resolved "https://registry.npm.taobao.org/@babel/helper-remap-async-to-generator/download/@babel/helper-remap-async-to-generator-7.13.0.tgz?cache=0&sync_timestamp=1614035099023&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-remap-async-to-generator%2Fdownload%2F%40babel%2Fhelper-remap-async-to-generator-7.13.0.tgz#376a760d9f7b4b2077a9dd05aa9c3927cadb2209"
......@@ -219,6 +260,16 @@
resolved "https://registry.npm.taobao.org/@babel/helper-validator-identifier/download/@babel/helper-validator-identifier-7.12.11.tgz#c9a1f021917dcb5ccf0d4e453e399022981fc9ed"
integrity sha1-yaHwIZF9y1zPDU5FPjmQIpgfye0=
"@babel/helper-validator-identifier@^7.15.7":
version "7.15.7"
resolved "https://rg.cnpmjs.org/@babel/helper-validator-identifier/download/@babel/helper-validator-identifier-7.15.7.tgz#220df993bfe904a4a6b02ab4f3385a5ebf6e2389"
integrity sha1-Ig35k7/pBKSmsCq08zhaXr9uI4k=
"@babel/helper-validator-option@^7.14.5":
version "7.14.5"
resolved "https://rg.cnpmjs.org/@babel/helper-validator-option/download/@babel/helper-validator-option-7.14.5.tgz#6e72a1fff18d5dfcb878e1e62f1a021c4b72d5a3"
integrity sha1-bnKh//GNXfy4eOHmLxoCHEty1aM=
"@babel/helper-wrap-function@^7.13.0":
version "7.13.0"
resolved "https://registry.npm.taobao.org/@babel/helper-wrap-function/download/@babel/helper-wrap-function-7.13.0.tgz?cache=0&sync_timestamp=1614034233760&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fhelper-wrap-function%2Fdownload%2F%40babel%2Fhelper-wrap-function-7.13.0.tgz#bdb5c66fda8526ec235ab894ad53a1235c79fcc4"
......@@ -566,6 +617,18 @@
"@babel/helper-plugin-utils" "^7.12.13"
semver "^5.5.1"
"@babel/plugin-transform-runtime@^7.13.10":
version "7.16.5"
resolved "https://rg.cnpmjs.org/@babel/plugin-transform-runtime/download/@babel/plugin-transform-runtime-7.16.5.tgz#0cc3f01d69f299d5a42cd9ec43b92ea7a777b8db"
integrity sha512-gxpfS8XQWDbQ8oP5NcmpXxtEgCJkbO+W9VhZlOhr0xPyVaRjAQPOv7ZDj9fg0d5s9+NiVvMCE6gbkEkcsxwGRw==
dependencies:
"@babel/helper-module-imports" "^7.16.0"
"@babel/helper-plugin-utils" "^7.16.5"
babel-plugin-polyfill-corejs2 "^0.3.0"
babel-plugin-polyfill-corejs3 "^0.4.0"
babel-plugin-polyfill-regenerator "^0.3.0"
semver "^6.3.0"
"@babel/plugin-transform-shorthand-properties@^7.0.0":
version "7.12.13"
resolved "https://registry.npm.taobao.org/@babel/plugin-transform-shorthand-properties/download/@babel/plugin-transform-shorthand-properties-7.12.13.tgz?cache=0&sync_timestamp=1612314760117&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fplugin-transform-shorthand-properties%2Fdownload%2F%40babel%2Fplugin-transform-shorthand-properties-7.12.13.tgz#db755732b70c539d504c6390d9ce90fe64aff7ad"
......@@ -687,6 +750,14 @@
lodash "^4.17.19"
to-fast-properties "^2.0.0"
"@babel/types@^7.16.0":
version "7.16.0"
resolved "https://rg.cnpmjs.org/@babel/types/download/@babel/types-7.16.0.tgz#db3b313804f96aadd0b776c4823e127ad67289ba"
integrity sha1-2zsxOAT5aq3Qt3bEgj4SetZyibo=
dependencies:
"@babel/helper-validator-identifier" "^7.15.7"
to-fast-properties "^2.0.0"
"@bang88/react-native-ultimate-listview@^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/@bang88/react-native-ultimate-listview/-/react-native-ultimate-listview-4.0.0.tgz#f8c0daee1d091ea5b81891501d7f75d4717c4347"
......@@ -848,6 +919,17 @@
"@types/istanbul-reports" "^1.1.1"
"@types/yargs" "^13.0.0"
"@jest/types@^26.6.2":
version "26.6.2"
resolved "https://rg.cnpmjs.org/@jest/types/download/@jest/types-26.6.2.tgz#bef5a532030e1d88a2f5a6d933f84e97226ed48e"
integrity sha1-vvWlMgMOHYii9abZM/hOlyJu1I4=
dependencies:
"@types/istanbul-lib-coverage" "^2.0.0"
"@types/istanbul-reports" "^3.0.0"
"@types/node" "*"
"@types/yargs" "^15.0.0"
chalk "^4.0.0"
"@react-native-community/cameraroll@^4.0.4":
version "4.0.4"
resolved "https://registry.yarnpkg.com/@react-native-community/cameraroll/-/cameraroll-4.0.4.tgz#3e2567ce54e3985e8e0a51832dfa0e1c5317f75b"
......@@ -980,6 +1062,31 @@
"@types/istanbul-lib-coverage" "*"
"@types/istanbul-lib-report" "*"
"@types/istanbul-reports@^3.0.0":
version "3.0.1"
resolved "https://rg.cnpmjs.org/@types/istanbul-reports/download/@types/istanbul-reports-3.0.1.tgz#9153fe98bba2bd565a63add9436d6f0d7f8468ff"
integrity sha1-kVP+mLuivVZaY63ZQ21vDX+EaP8=
dependencies:
"@types/istanbul-lib-report" "*"
"@types/jest@^26.0.22":
version "26.0.24"
resolved "https://rg.cnpmjs.org/@types/jest/download/@types/jest-26.0.24.tgz#943d11976b16739185913a1936e0de0c4a7d595a"
integrity sha1-lD0Rl2sWc5GFkToZNuDeDEp9WVo=
dependencies:
jest-diff "^26.0.0"
pretty-format "^26.0.0"
"@types/node@*":
version "17.0.0"
resolved "https://rg.cnpmjs.org/@types/node/download/@types/node-17.0.0.tgz#62797cee3b8b497f6547503b2312254d4fe3c2bb"
integrity sha512-eMhwJXc931Ihh4tkU+Y7GiLzT/y/DBNpNtr4yU9O2w3SYBsr9NaOPhQlLKRmoWtI54uNwuo0IOUFQjVOTZYRvw==
"@types/prop-types@*":
version "15.7.4"
resolved "https://rg.cnpmjs.org/@types/prop-types/download/@types/prop-types-15.7.4.tgz#fcf7205c25dff795ee79af1e30da2c9790808f11"
integrity sha1-/PcgXCXf95Xuea8eMNosl5CAjxE=
"@types/ramda@^0.27.39":
version "0.27.39"
resolved "https://registry.npm.taobao.org/@types/ramda/download/@types/ramda-0.27.39.tgz?cache=0&sync_timestamp=1615893039310&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Framda%2Fdownload%2F%40types%2Framda-0.27.39.tgz#7541d9d745a2003c8f635897dff8c65c12be9327"
......@@ -987,6 +1094,34 @@
dependencies:
ts-toolbelt "^6.15.1"
"@types/react-native@^0.64.2":
version "0.64.19"
resolved "https://rg.cnpmjs.org/@types/react-native/download/@types/react-native-0.64.19.tgz#2b888c082ad293fa0fa6ae34c5e9457cfb38e50a"
integrity sha512-bT62QhaPvOKFGmlfURIC98ILjUDoIFrc2Bn5EzL3qciZrT91vHwkxFOkuEyQJy+DWaHCa2z3IrtIEJywkGu/Bg==
dependencies:
"@types/react" "*"
"@types/react-test-renderer@^17.0.1":
version "17.0.1"
resolved "https://rg.cnpmjs.org/@types/react-test-renderer/download/@types/react-test-renderer-17.0.1.tgz#3120f7d1c157fba9df0118dae20cb0297ee0e06b"
integrity sha1-MSD30cFX+6nfARja4gywKX7g4Gs=
dependencies:
"@types/react" "*"
"@types/react@*", "@types/react@^17.0.3":
version "17.0.37"
resolved "https://rg.cnpmjs.org/@types/react/download/@types/react-17.0.37.tgz#6884d0aa402605935c397ae689deed115caad959"
integrity sha512-2FS1oTqBGcH/s0E+CjrCCR9+JMpsu9b69RTFO+40ua43ZqP5MmQ4iUde/dMjWR909KxZwmOQIFq6AV6NjEG5xg==
dependencies:
"@types/prop-types" "*"
"@types/scheduler" "*"
csstype "^3.0.2"
"@types/scheduler@*":
version "0.16.2"
resolved "https://rg.cnpmjs.org/@types/scheduler/download/@types/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39"
integrity sha1-GmL4lSVyPd4kuhsBsJK/XfitTTk=
"@types/shallowequal@^1.1.1":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@types/shallowequal/-/shallowequal-1.1.1.tgz#aad262bb3f2b1257d94c71d545268d592575c9b1"
......@@ -1009,6 +1144,13 @@
dependencies:
"@types/yargs-parser" "*"
"@types/yargs@^15.0.0":
version "15.0.14"
resolved "https://rg.cnpmjs.org/@types/yargs/download/@types/yargs-15.0.14.tgz#26d821ddb89e70492160b66d10a0eb6df8f6fb06"
integrity sha1-Jtgh3biecEkhYLZtEKDrbfj2+wY=
dependencies:
"@types/yargs-parser" "*"
abab@^2.0.0:
version "2.0.5"
resolved "https://registry.npm.taobao.org/abab/download/abab-2.0.5.tgz?cache=0&sync_timestamp=1599850271460&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fabab%2Fdownload%2Fabab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a"
......@@ -1139,7 +1281,7 @@ ansi-styles@^3.2.0, ansi-styles@^3.2.1:
dependencies:
color-convert "^1.9.0"
ansi-styles@^4.1.0:
ansi-styles@^4.0.0, ansi-styles@^4.1.0:
version "4.3.0"
resolved "https://registry.npm.taobao.org/ansi-styles/download/ansi-styles-4.3.0.tgz?cache=0&sync_timestamp=1611325747047&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fansi-styles%2Fdownload%2Fansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
integrity sha1-7dgDYornHATIWuegkG7a00tkiTc=
......@@ -1371,6 +1513,41 @@ babel-plugin-jest-hoist@^24.9.0:
dependencies:
"@types/babel__traverse" "^7.0.6"
babel-plugin-module-resolver@^4.1.0:
version "4.1.0"
resolved "https://rg.cnpmjs.org/babel-plugin-module-resolver/download/babel-plugin-module-resolver-4.1.0.tgz#22a4f32f7441727ec1fbf4967b863e1e3e9f33e2"
integrity sha1-IqTzL3RBcn7B+/SWe4Y+Hj6fM+I=
dependencies:
find-babel-config "^1.2.0"
glob "^7.1.6"
pkg-up "^3.1.0"
reselect "^4.0.0"
resolve "^1.13.1"
babel-plugin-polyfill-corejs2@^0.3.0:
version "0.3.0"
resolved "https://rg.cnpmjs.org/babel-plugin-polyfill-corejs2/download/babel-plugin-polyfill-corejs2-0.3.0.tgz#407082d0d355ba565af24126fb6cb8e9115251fd"
integrity sha512-wMDoBJ6uG4u4PNFh72Ty6t3EgfA91puCuAwKIazbQlci+ENb/UU9A3xG5lutjUIiXCIn1CY5L15r9LimiJyrSA==
dependencies:
"@babel/compat-data" "^7.13.11"
"@babel/helper-define-polyfill-provider" "^0.3.0"
semver "^6.1.1"
babel-plugin-polyfill-corejs3@^0.4.0:
version "0.4.0"
resolved "https://rg.cnpmjs.org/babel-plugin-polyfill-corejs3/download/babel-plugin-polyfill-corejs3-0.4.0.tgz#0b571f4cf3d67f911512f5c04842a7b8e8263087"
integrity sha512-YxFreYwUfglYKdLUGvIF2nJEsGwj+RhWSX/ije3D2vQPOXuyMLMtg/cCGMDpOA7Nd+MwlNdnGODbd2EwUZPlsw==
dependencies:
"@babel/helper-define-polyfill-provider" "^0.3.0"
core-js-compat "^3.18.0"
babel-plugin-polyfill-regenerator@^0.3.0:
version "0.3.0"
resolved "https://rg.cnpmjs.org/babel-plugin-polyfill-regenerator/download/babel-plugin-polyfill-regenerator-0.3.0.tgz#9ebbcd7186e1a33e21c5e20cae4e7983949533be"
integrity sha512-dhAPTDLGoMW5/84wkgwiLRwMnio2i1fUe53EuvtKMv0pn2p3S8OCoV1xAzfJPl0KOX7IB89s2ib85vbYiea3jg==
dependencies:
"@babel/helper-define-polyfill-provider" "^0.3.0"
babel-plugin-syntax-trailing-function-commas@^7.0.0-beta.0:
version "7.0.0-beta.0"
resolved "https://registry.npm.taobao.org/babel-plugin-syntax-trailing-function-commas/download/babel-plugin-syntax-trailing-function-commas-7.0.0-beta.0.tgz#aa213c1435e2bffeb6fca842287ef534ad05d5cf"
......@@ -1538,6 +1715,17 @@ browser-resolve@^1.11.3:
dependencies:
resolve "1.1.7"
browserslist@^4.17.5, browserslist@^4.19.1:
version "4.19.1"
resolved "https://rg.cnpmjs.org/browserslist/download/browserslist-4.19.1.tgz#4ac0435b35ab655896c31d53018b6dd5e9e4c9a3"
integrity sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==
dependencies:
caniuse-lite "^1.0.30001286"
electron-to-chromium "^1.4.17"
escalade "^3.1.1"
node-releases "^2.0.1"
picocolors "^1.0.0"
bser@2.1.1:
version "2.1.1"
resolved "https://registry.npm.taobao.org/bser/download/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05"
......@@ -1627,6 +1815,16 @@ camelcase@^5.0.0, camelcase@^5.3.1:
resolved "https://registry.npm.taobao.org/camelcase/download/camelcase-5.3.1.tgz?cache=0&sync_timestamp=1603921884289&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcamelcase%2Fdownload%2Fcamelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
integrity sha1-48mzFWnhBoEd8kL3FXJaH0xJQyA=
camelize@^1.0.0:
version "1.0.0"
resolved "https://rg.cnpmjs.org/camelize/download/camelize-1.0.0.tgz#164a5483e630fa4321e5af07020e531831b2609b"
integrity sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs=
caniuse-lite@^1.0.30001286:
version "1.0.30001287"
resolved "https://rg.cnpmjs.org/caniuse-lite/download/caniuse-lite-1.0.30001287.tgz#5fab6a46ab9e47146d5dd35abfe47beaf8073c71"
integrity sha512-4udbs9bc0hfNrcje++AxBuc6PfLNHwh3PO9kbwnfCQWyqtlzg3py0YgFu8jyRTTo85VAz4U+VLxSlID09vNtWA==
capture-exit@^1.2.0:
version "1.2.0"
resolved "https://registry.npm.taobao.org/capture-exit/download/capture-exit-1.2.0.tgz#1c5fcc489fd0ab00d4f1ac7ae1072e3173fbab6f"
......@@ -1666,6 +1864,14 @@ chalk@^2.0.0, chalk@^2.0.1, chalk@^2.3.0, chalk@^2.4.1, chalk@^2.4.2:
escape-string-regexp "^1.0.5"
supports-color "^5.3.0"
chalk@^4.0.0:
version "4.1.2"
resolved "https://rg.cnpmjs.org/chalk/download/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
integrity sha1-qsTit3NKdAhnrrFr8CqtVWoeegE=
dependencies:
ansi-styles "^4.1.0"
supports-color "^7.1.0"
chalk@^4.1.0:
version "4.1.0"
resolved "https://registry.npm.taobao.org/chalk/download/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a"
......@@ -1889,6 +2095,14 @@ copy-descriptor@^0.1.0:
resolved "https://registry.npm.taobao.org/copy-descriptor/download/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=
core-js-compat@^3.18.0:
version "3.20.0"
resolved "https://rg.cnpmjs.org/core-js-compat/download/core-js-compat-3.20.0.tgz#fd704640c5a213816b6d10ec0192756111e2c9d1"
integrity sha512-relrah5h+sslXssTTOkvqcC/6RURifB0W5yhYBdBkaPYa5/2KBMiog3XiD+s3TwEHWxInWVv4Jx2/Lw0vng+IQ==
dependencies:
browserslist "^4.19.1"
semver "7.0.0"
core-js@^2.2.2, core-js@^2.4.0, core-js@^2.4.1:
version "2.6.12"
resolved "https://registry.npm.taobao.org/core-js/download/core-js-2.6.12.tgz?cache=0&sync_timestamp=1611040749668&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcore-js%2Fdownload%2Fcore-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec"
......@@ -1899,7 +2113,7 @@ core-util-is@1.0.2, core-util-is@~1.0.0:
resolved "https://registry.npm.taobao.org/core-util-is/download/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
cosmiconfig@^5.0.5:
cosmiconfig@^5.0.0, cosmiconfig@^5.0.5:
version "5.2.1"
resolved "https://registry.npm.taobao.org/cosmiconfig/download/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a"
integrity sha1-BA9yaAnFked6F8CjYmykW08Wixo=
......@@ -1937,6 +2151,51 @@ cross-spawn@^6.0.0:
shebang-command "^1.2.0"
which "^1.2.9"
css-color-keywords@^1.0.0:
version "1.0.0"
resolved "https://rg.cnpmjs.org/css-color-keywords/download/css-color-keywords-1.0.0.tgz#fea2616dc676b2962686b3af8dbdbe180b244e05"
integrity sha1-/qJhbcZ2spYmhrOvjb2+GAskTgU=
css-mediaquery@^0.1.2:
version "0.1.2"
resolved "https://rg.cnpmjs.org/css-mediaquery/download/css-mediaquery-0.1.2.tgz#6a2c37344928618631c54bd33cedd301da18bea0"
integrity sha1-aiw3NEkoYYYxxUvTPO3TAdoYvqA=
css-parse@~2.0.0:
version "2.0.0"
resolved "https://rg.cnpmjs.org/css-parse/download/css-parse-2.0.0.tgz#a468ee667c16d81ccf05c58c38d2a97c780dbfd4"
integrity sha1-pGjuZnwW2BzPBcWMONKpfHgNv9Q=
dependencies:
css "^2.0.0"
css-to-react-native-transform@^1.8.1:
version "1.9.0"
resolved "https://rg.cnpmjs.org/css-to-react-native-transform/download/css-to-react-native-transform-1.9.0.tgz#63369f479048ab7662f5320f8010840ad91344e7"
integrity sha1-YzafR5BIq3Zi9TIPgBCECtkTROc=
dependencies:
css "^2.2.4"
css-mediaquery "^0.1.2"
css-to-react-native "^2.3.0"
css-to-react-native@^2.3.0:
version "2.3.2"
resolved "https://rg.cnpmjs.org/css-to-react-native/download/css-to-react-native-2.3.2.tgz#e75e2f8f7aa385b4c3611c52b074b70a002f2e7d"
integrity sha1-514vj3qjhbTDYRxSsHS3CgAvLn0=
dependencies:
camelize "^1.0.0"
css-color-keywords "^1.0.0"
postcss-value-parser "^3.3.0"
css@^2.0.0, css@^2.2.4:
version "2.2.4"
resolved "https://rg.cnpmjs.org/css/download/css-2.2.4.tgz#c646755c73971f2bba6a601e2cf2fd71b1298929"
integrity sha1-xkZ1XHOXHyu6amAeLPL9cbEpiSk=
dependencies:
inherits "^2.0.3"
source-map "^0.6.1"
source-map-resolve "^0.5.2"
urix "^0.1.0"
cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0":
version "0.3.8"
resolved "https://registry.npm.taobao.org/cssom/download/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a"
......@@ -1949,6 +2208,11 @@ cssstyle@^1.0.0:
dependencies:
cssom "0.3.x"
csstype@^3.0.2:
version "3.0.10"
resolved "https://rg.cnpmjs.org/csstype/download/csstype-3.0.10.tgz#2ad3a7bed70f35b965707c092e5f30b327c290e5"
integrity sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==
dashdash@^1.12.0:
version "1.14.1"
resolved "https://registry.npm.taobao.org/dashdash/download/dashdash-1.14.1.tgz?cache=0&sync_timestamp=1601073602368&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdashdash%2Fdownload%2Fdashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
......@@ -1996,6 +2260,13 @@ debug@^3.1.0:
dependencies:
ms "^2.1.1"
debug@~3.1.0:
version "3.1.0"
resolved "https://rg.cnpmjs.org/debug/download/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
integrity sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=
dependencies:
ms "2.0.0"
decamelize@^1.1.1, decamelize@^1.2.0:
version "1.2.0"
resolved "https://registry.npm.taobao.org/decamelize/download/decamelize-1.2.0.tgz?cache=0&sync_timestamp=1610348634503&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdecamelize%2Fdownload%2Fdecamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
......@@ -2099,6 +2370,11 @@ diff-sequences@^24.9.0:
resolved "https://registry.npm.taobao.org/diff-sequences/download/diff-sequences-24.9.0.tgz?cache=0&sync_timestamp=1607352548704&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdiff-sequences%2Fdownload%2Fdiff-sequences-24.9.0.tgz#5715d6244e2aa65f48bba0bc972db0b0b11e95b5"
integrity sha1-VxXWJE4qpl9Iu6C8ly2wsLEelbU=
diff-sequences@^26.6.2:
version "26.6.2"
resolved "https://rg.cnpmjs.org/diff-sequences/download/diff-sequences-26.6.2.tgz#48ba99157de1923412eed41db6b6d4aa9ca7c0b1"
integrity sha1-SLqZFX3hkjQS7tQdtrbUqpynwLE=
diff@^4.0.1:
version "4.0.2"
resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
......@@ -2129,6 +2405,11 @@ ee-first@1.1.1:
resolved "https://registry.npm.taobao.org/ee-first/download/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
electron-to-chromium@^1.4.17:
version "1.4.24"
resolved "https://rg.cnpmjs.org/electron-to-chromium/download/electron-to-chromium-1.4.24.tgz#9cf8a92d5729c480ee47ff0aa5555f57467ae2fa"
integrity sha512-erwx5r69B/WFfFuF2jcNN0817BfDBdC4765kQ6WltOMuwsimlQo3JTEq0Cle+wpHralwdeX3OfAtw/mHxPK0Wg==
emoji-regex@^7.0.1:
version "7.0.3"
resolved "https://registry.npm.taobao.org/emoji-regex/download/emoji-regex-7.0.3.tgz?cache=0&sync_timestamp=1611911479256&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Femoji-regex%2Fdownload%2Femoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156"
......@@ -2207,6 +2488,11 @@ es-to-primitive@^1.2.1:
is-date-object "^1.0.1"
is-symbol "^1.0.2"
escalade@^3.1.1:
version "3.1.1"
resolved "https://rg.cnpmjs.org/escalade/download/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
integrity sha1-2M/ccACWXFoBdLSoLqpcBVJ0LkA=
escape-html@~1.0.3:
version "1.0.3"
resolved "https://registry.npm.taobao.org/escape-html/download/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
......@@ -2557,6 +2843,14 @@ finalhandler@1.1.2:
statuses "~1.5.0"
unpipe "~1.0.0"
find-babel-config@^1.2.0:
version "1.2.0"
resolved "https://rg.cnpmjs.org/find-babel-config/download/find-babel-config-1.2.0.tgz#a9b7b317eb5b9860cda9d54740a8c8337a2283a2"
integrity sha1-qbezF+tbmGDNqdVHQKjIM3oig6I=
dependencies:
json5 "^0.5.1"
path-exists "^3.0.0"
find-cache-dir@^2.0.0:
version "2.1.0"
resolved "https://registry.npm.taobao.org/find-cache-dir/download/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7"
......@@ -3002,6 +3296,13 @@ image-size@^0.6.0:
resolved "https://registry.npm.taobao.org/image-size/download/image-size-0.6.3.tgz?cache=0&sync_timestamp=1603731285656&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fimage-size%2Fdownload%2Fimage-size-0.6.3.tgz#e7e5c65bb534bd7cdcedd6cb5166272a85f75fb2"
integrity sha1-5+XGW7U0vXzc7dbLUWYnKoX3X7I=
import-cwd@^2.0.0:
version "2.1.0"
resolved "https://rg.cnpmjs.org/import-cwd/download/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9"
integrity sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk=
dependencies:
import-from "^2.1.0"
import-fresh@^2.0.0:
version "2.0.0"
resolved "https://registry.npm.taobao.org/import-fresh/download/import-fresh-2.0.0.tgz?cache=0&sync_timestamp=1608469472392&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fimport-fresh%2Fdownload%2Fimport-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546"
......@@ -3010,6 +3311,13 @@ import-fresh@^2.0.0:
caller-path "^2.0.0"
resolve-from "^3.0.0"
import-from@^2.1.0:
version "2.1.0"
resolved "https://rg.cnpmjs.org/import-from/download/import-from-2.1.0.tgz#335db7f2a7affd53aaa471d4b8021dee36b7f3b1"
integrity sha1-M1238qev/VOqpHHUuAId7ja387E=
dependencies:
resolve-from "^3.0.0"
import-local@^2.0.0:
version "2.0.0"
resolved "https://registry.npm.taobao.org/import-local/download/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d"
......@@ -3464,6 +3772,16 @@ jest-diff@^24.9.0:
jest-get-type "^24.9.0"
pretty-format "^24.9.0"
jest-diff@^26.0.0:
version "26.6.2"
resolved "https://rg.cnpmjs.org/jest-diff/download/jest-diff-26.6.2.tgz#1aa7468b52c3a68d7d5c5fdcdfcd5e49bd164394"
integrity sha1-GqdGi1LDpo19XF/c381eSb0WQ5Q=
dependencies:
chalk "^4.0.0"
diff-sequences "^26.6.2"
jest-get-type "^26.3.0"
pretty-format "^26.6.2"
jest-docblock@^24.3.0:
version "24.9.0"
resolved "https://registry.npm.taobao.org/jest-docblock/download/jest-docblock-24.9.0.tgz?cache=0&sync_timestamp=1607352701834&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-docblock%2Fdownload%2Fjest-docblock-24.9.0.tgz#7970201802ba560e1c4092cc25cbedf5af5a8ce2"
......@@ -3510,6 +3828,11 @@ jest-get-type@^24.9.0:
resolved "https://registry.npm.taobao.org/jest-get-type/download/jest-get-type-24.9.0.tgz?cache=0&sync_timestamp=1607352755729&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjest-get-type%2Fdownload%2Fjest-get-type-24.9.0.tgz#1684a0c8a50f2e4901b6644ae861f579eed2ef0e"
integrity sha1-FoSgyKUPLkkBtmRK6GH1ee7S7w4=
jest-get-type@^26.3.0:
version "26.3.0"
resolved "https://rg.cnpmjs.org/jest-get-type/download/jest-get-type-26.3.0.tgz#e97dc3c3f53c2b406ca7afaed4493b1d099199e0"
integrity sha1-6X3Dw/U8K0Bsp6+u1Ek7HQmRmeA=
jest-haste-map@24.0.0-alpha.6:
version "24.0.0-alpha.6"
resolved "https://registry.npm.taobao.org/jest-haste-map/download/jest-haste-map-24.0.0-alpha.6.tgz#fb2c785080f391b923db51846b86840d0d773076"
......@@ -3874,6 +4197,11 @@ json-stringify-safe@~5.0.1:
resolved "https://registry.npm.taobao.org/json-stringify-safe/download/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=
json5@^0.5.1:
version "0.5.1"
resolved "https://rg.cnpmjs.org/json5/download/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821"
integrity sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=
json5@^2.1.2:
version "2.2.0"
resolved "https://registry.npm.taobao.org/json5/download/json5-2.2.0.tgz?cache=0&sync_timestamp=1612146079519&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjson5%2Fdownload%2Fjson5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3"
......@@ -4574,6 +4902,11 @@ mkdirp@^0.5.1, mkdirp@^0.5.3:
dependencies:
minimist "^1.2.5"
mkdirp@~1.0.4:
version "1.0.4"
resolved "https://rg.cnpmjs.org/mkdirp/download/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
integrity sha1-PrXtYmInVteaXw4qIh3+utdcL34=
moment@2.29.1, moment@^2.22.1:
version "2.29.1"
resolved "https://registry.npm.taobao.org/moment/download/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3"
......@@ -4696,6 +5029,11 @@ node-notifier@^5.2.1, node-notifier@^5.4.2:
shellwords "^0.1.1"
which "^1.3.0"
node-releases@^2.0.1:
version "2.0.1"
resolved "https://rg.cnpmjs.org/node-releases/download/node-releases-2.0.1.tgz#3d1d395f204f1f2f29a54358b9fb678765ad2fc5"
integrity sha1-PR05XyBPHy8ppUNYuftnh2WtL8U=
normalize-css-color@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/normalize-css-color/-/normalize-css-color-1.0.2.tgz#02991e97cccec6623fe573afbbf0de6a1f3e9f8d"
......@@ -5068,6 +5406,11 @@ performance-now@^2.1.0:
resolved "https://registry.npm.taobao.org/performance-now/download/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=
picocolors@^1.0.0:
version "1.0.0"
resolved "https://rg.cnpmjs.org/picocolors/download/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
integrity sha1-y1vcdP8/UYkiNur3nWi8RFZKuBw=
pify@^2.0.0:
version "2.3.0"
resolved "https://registry.npm.taobao.org/pify/download/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
......@@ -5097,6 +5440,13 @@ pkg-dir@^3.0.0:
dependencies:
find-up "^3.0.0"
pkg-up@^3.1.0:
version "3.1.0"
resolved "https://rg.cnpmjs.org/pkg-up/download/pkg-up-3.1.0.tgz#100ec235cc150e4fd42519412596a28512a0def5"
integrity sha1-EA7CNcwVDk/UJRlBJZaihRKg3vU=
dependencies:
find-up "^3.0.0"
plist@3.0.1, plist@^3.0.0, plist@^3.0.1:
version "3.0.1"
resolved "https://registry.npm.taobao.org/plist/download/plist-3.0.1.tgz#a9b931d17c304e8912ef0ba3bdd6182baf2e1f8c"
......@@ -5127,6 +5477,19 @@ posix-character-classes@^0.1.0:
resolved "https://registry.npm.taobao.org/posix-character-classes/download/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"
integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=
postcss-load-config@^2.0.0:
version "2.1.2"
resolved "https://rg.cnpmjs.org/postcss-load-config/download/postcss-load-config-2.1.2.tgz#c5ea504f2c4aef33c7359a34de3573772ad7502a"
integrity sha1-xepQTyxK7zPHNZo03jVzdyrXUCo=
dependencies:
cosmiconfig "^5.0.0"
import-cwd "^2.0.0"
postcss-value-parser@^3.3.0:
version "3.3.1"
resolved "https://rg.cnpmjs.org/postcss-value-parser/download/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281"
integrity sha1-n/giVH4okyE88cMO+lGsX9G6goE=
prelude-ls@~1.1.2:
version "1.1.2"
resolved "https://registry.npm.taobao.org/prelude-ls/download/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
......@@ -5155,6 +5518,16 @@ pretty-format@^24.9.0:
ansi-styles "^3.2.0"
react-is "^16.8.4"
pretty-format@^26.0.0, pretty-format@^26.6.2:
version "26.6.2"
resolved "https://rg.cnpmjs.org/pretty-format/download/pretty-format-26.6.2.tgz#e35c2705f14cb7fe2fe94fa078345b444120fc93"
integrity sha1-41wnBfFMt/4v6U+geDRbREEg/JM=
dependencies:
"@jest/types" "^26.6.2"
ansi-regex "^5.0.0"
ansi-styles "^4.0.0"
react-is "^17.0.1"
process-nextick-args@~2.0.0:
version "2.0.1"
resolved "https://registry.npm.taobao.org/process-nextick-args/download/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
......@@ -5307,6 +5680,11 @@ react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.3, react-is@^16.8.4, react-is
resolved "https://registry.npm.taobao.org/react-is/download/react-is-16.13.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Freact-is%2Fdownload%2Freact-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
integrity sha1-eJcppNw23imZ3BVt1sHZwYzqVqQ=
react-is@^17.0.1:
version "17.0.2"
resolved "https://rg.cnpmjs.org/react-is/download/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0"
integrity sha1-5pHUqOnHiTZWVVOas3J2Kw77VPA=
react-lifecycles-compat@^3.0.4:
version "3.0.4"
resolved "https://registry.npm.taobao.org/react-lifecycles-compat/download/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
......@@ -5396,6 +5774,15 @@ react-native-pager-view@5.2.1:
resolved "https://rg.cnpmjs.org/react-native-pager-view/download/react-native-pager-view-5.2.1.tgz#ad69a6035edd998771daf302830f73602e5204a9"
integrity sha1-rWmmA17dmYdx2vMCgw9zYC5SBKk=
react-native-postcss-transformer@^1.2.4:
version "1.2.4"
resolved "https://rg.cnpmjs.org/react-native-postcss-transformer/download/react-native-postcss-transformer-1.2.4.tgz#3e1c9f1c0e36764a76516c5fd584e7f10c994014"
integrity sha1-PhyfHA42dkp2UWxf1YTn8QyZQBQ=
dependencies:
css-to-react-native-transform "^1.8.1"
postcss-load-config "^2.0.0"
semver "^5.6.0"
react-native-root-siblings@^3.0.0:
version "3.2.3"
resolved "https://registry.npm.taobao.org/react-native-root-siblings/download/react-native-root-siblings-3.2.3.tgz#df5a1cff3a3a1f433f57320e1cae719f1b15a3f2"
......@@ -5445,6 +5832,14 @@ react-native-splash-screen@3.2.0:
resolved "https://registry.npm.taobao.org/react-native-splash-screen/download/react-native-splash-screen-3.2.0.tgz#d47ec8557b1ba988ee3ea98d01463081b60fff45"
integrity sha1-1H7IVXsbqYjuPqmNAUYwgbYP/0U=
react-native-stylus-transformer@^1.2.0:
version "1.2.0"
resolved "https://rg.cnpmjs.org/react-native-stylus-transformer/download/react-native-stylus-transformer-1.2.0.tgz#5e12a7dba5fc75fb2cafc300793fc2a43232a7af"
integrity sha1-XhKn26X8dfssr8MAeT/CpDIyp68=
dependencies:
css-to-react-native-transform "^1.8.1"
semver "^5.6.0"
react-native-tab-view@^1.2.0, react-native-tab-view@^1.4.1:
version "1.4.1"
resolved "https://registry.npm.taobao.org/react-native-tab-view/download/react-native-tab-view-1.4.1.tgz?cache=0&sync_timestamp=1602059290475&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Freact-native-tab-view%2Fdownload%2Freact-native-tab-view-1.4.1.tgz#f113cd87485808f0c991abec937f70fa380478b9"
......@@ -5690,6 +6085,11 @@ redux@4.0.1:
loose-envify "^1.4.0"
symbol-observable "^1.2.0"
reflect-metadata@^0.1.13:
version "0.1.13"
resolved "https://rg.cnpmjs.org/reflect-metadata/download/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08"
integrity sha1-Z648pXyXKiqhZCsQ/jY/4y1J3Ag=
regenerate-unicode-properties@^8.2.0:
version "8.2.0"
resolved "https://registry.npm.taobao.org/regenerate-unicode-properties/download/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec"
......@@ -5835,6 +6235,11 @@ requires-port@^1.0.0:
resolved "https://registry.npm.taobao.org/requires-port/download/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=
reselect@^4.0.0:
version "4.1.5"
resolved "https://rg.cnpmjs.org/reselect/download/reselect-4.1.5.tgz#852c361247198da6756d07d9296c2b51eddb79f6"
integrity sha512-uVdlz8J7OO+ASpBYoz1Zypgx0KasCY20H+N8JD13oUMtPvSHQuscrHop4KbXrbsBcdB9Ds7lVK7eRkBIfO43vQ==
resolve-cwd@^2.0.0:
version "2.0.0"
resolved "https://registry.npm.taobao.org/resolve-cwd/download/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a"
......@@ -5865,7 +6270,7 @@ resolve@^1.10.0, resolve@^1.5.0:
is-core-module "^2.1.0"
path-parse "^1.0.6"
resolve@^1.3.2:
resolve@^1.13.1, resolve@^1.14.2, resolve@^1.3.2:
version "1.20.0"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975"
integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==
......@@ -5965,7 +6370,7 @@ safe-regex@^1.1.0:
dependencies:
ret "~0.1.10"
"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0:
"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@^2.1.2, safer-buffer@~2.1.0:
version "2.1.2"
resolved "https://registry.npm.taobao.org/safer-buffer/download/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
integrity sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo=
......@@ -6002,7 +6407,7 @@ sane@^4.0.3:
minimist "^1.1.1"
walker "~1.0.5"
sax@^1.2.4:
sax@^1.2.4, sax@~1.2.4:
version "1.2.4"
resolved "https://registry.npm.taobao.org/sax/download/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
integrity sha1-KBYjTiN4vdxOU1T6tcqold9xANk=
......@@ -6025,7 +6430,12 @@ scheduler@^0.13.3:
resolved "https://registry.npm.taobao.org/semver/download/semver-5.7.1.tgz?cache=0&sync_timestamp=1606854493763&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
integrity sha1-qVT5Ma66UI0we78Gnv8MAclhFvc=
semver@^6.0.0, semver@^6.1.1, semver@^6.2.0:
semver@7.0.0:
version "7.0.0"
resolved "https://rg.cnpmjs.org/semver/download/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e"
integrity sha1-XzyjV2HkfgWyBsba/yz4FPAxa44=
semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0:
version "6.3.0"
resolved "https://registry.npm.taobao.org/semver/download/semver-6.3.0.tgz?cache=0&sync_timestamp=1606852064928&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
integrity sha1-7gpkyK9ejO6mdoexM3YeG+y9HT0=
......@@ -6219,7 +6629,7 @@ socks@^2.3.3:
ip "^1.1.5"
smart-buffer "^4.1.0"
source-map-resolve@^0.5.0:
source-map-resolve@^0.5.0, source-map-resolve@^0.5.2:
version "0.5.3"
resolved "https://registry.npm.taobao.org/source-map-resolve/download/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a"
integrity sha1-GQhmvs51U+H48mei7oLGBrVQmho=
......@@ -6253,6 +6663,11 @@ source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1:
resolved "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
integrity sha1-dHIq8y6WFOnCh6jQu95IteLxomM=
source-map@^0.7.3:
version "0.7.3"
resolved "https://rg.cnpmjs.org/source-map/download/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383"
integrity sha1-UwL4FpAxc1ImVECS5kmB91F1A4M=
spdx-correct@^3.0.0:
version "3.1.1"
resolved "https://registry.npm.taobao.org/spdx-correct/download/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9"
......@@ -6474,6 +6889,20 @@ strip-eof@^1.0.0:
resolved "https://registry.npm.taobao.org/strip-eof/download/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=
stylus@^0.54.8:
version "0.54.8"
resolved "https://rg.cnpmjs.org/stylus/download/stylus-0.54.8.tgz#3da3e65966bc567a7b044bfe0eece653e099d147"
integrity sha1-PaPmWWa8Vnp7BEv+DuzmU+CZ0Uc=
dependencies:
css-parse "~2.0.0"
debug "~3.1.0"
glob "^7.1.6"
mkdirp "~1.0.4"
safer-buffer "^2.1.2"
sax "~1.2.4"
semver "^6.3.0"
source-map "^0.7.3"
superagent-proxy@^2.0.0:
version "2.1.0"
resolved "https://registry.npm.taobao.org/superagent-proxy/download/superagent-proxy-2.1.0.tgz#34e91f9024fbace95f0a35c50c69edf2a0d331e2"
......@@ -6730,6 +7159,11 @@ typedarray@^0.0.6:
resolved "https://registry.npm.taobao.org/typedarray/download/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
typescript@^4.2.4:
version "4.5.4"
resolved "https://rg.cnpmjs.org/typescript/download/typescript-4.5.4.tgz#a17d3a0263bf5c8723b9c52f43c5084edf13c2e8"
integrity sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg==
ua-parser-js@^0.7.18:
version "0.7.23"
resolved "https://registry.npm.taobao.org/ua-parser-js/download/ua-parser-js-0.7.23.tgz?cache=0&sync_timestamp=1607577974704&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fua-parser-js%2Fdownload%2Fua-parser-js-0.7.23.tgz#704d67f951e13195fbcd3d78818577f5bc1d547b"
......
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 sign in to comment