Commit b657df24 by wong.peiyi

消耗明细

parent b9acd2ff
......@@ -14,7 +14,7 @@
"babel-plugin-import": "^1.13.3",
"dayjs": "^1.10.4",
"inversify": "^5.0.5",
"mobx": "^5.7.0",
"mobx": "^4.4",
"mobx-persist": "^0.4.1",
"mobx-react": "~6.0.0",
"moment": "2.29.1",
......
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')}>
<View style={[g(styles, 'checkbox-inner'), style]}>
{!!checked && <Image source={require('../../assets/images/ic_checked_blue.png')} />}
{isNotBlank(label) && <Text>{label}</Text>}
</View>
</TouchableWithoutFeedback>
)
}
......@@ -10,11 +10,11 @@
.select
width 100%
height 100%
padding 30px 0 40px
&-bd
width 100%
height 100%
padding 50px 30px
&-option
height 35px
......@@ -26,3 +26,14 @@
&-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
......@@ -9,7 +9,15 @@
*
*/
import React, { useEffect, useRef, useState, createRef } from 'react'
import { View, Text, TouchableOpacity, ScrollView, Animated } from 'react-native'
import {
View,
Text,
TouchableOpacity,
ScrollView,
Animated,
ActivityIndicator,
FlatList,
} from 'react-native'
import { Provider, Modal } from '@ant-design/react-native'
import { IOption } from 'bonehouse'
import * as R from 'ramda'
......@@ -23,6 +31,7 @@ type IModalProps = {
data: IOption[]
value: string | number
mask?: boolean
loading: boolean
title?: string
visible: boolean
onChange?: Function
......@@ -37,50 +46,63 @@ let scrollRef = null
* @return {*}
*/
export function SelectModal(props: IModalProps) {
const { data = [], value, mask, onChange, visible, title, onClose } = props
const { data = [], value, mask, onChange, visible, title, onClose, loading } = props
const [contentHeight, setContentHeight] = useState(300)
const [action, setAction] = useState(0)
useEffect(() => {
setContentHeight(35 * data.length + 100)
setContentHeight(35 * data.length + 70)
const idx = R.findIndex(R.propEq('value', value))(data)
if (idx > -1) {
scrollRef && scrollRef.scrollTo({ y: 35 * idx + 20 })
if (idx > 1) {
scrollRef && scrollRef.scrollToIndex({ animated: true, index: idx })
}
}, [data.length])
return (
<BottomModal contentHeight={contentHeight} visible={visible} onClose={onClose} action={action}>
<ScrollView style={g(styles, 'select')} ref={ref => (scrollRef = ref)}>
<View style={g(styles, 'select-bd')}>
{data.map(option => {
const Item = ({ item }) => {
return (
<TouchableOpacity
key={option.value}
style={g(styles, 'select-option')}
activeOpacity={0.8}
style={g(styles, 'select-option')}
onPress={() => {
onChange && onChange(option.value)
onChange && onChange(item.value)
setAction(action + 1)
}}
>
<Text
numberOfLines={1}
style={g(
styles,
value === option.value
? ['select-option__text-active']
: ['select-option__text'],
)}
style={g(styles, {
'select-option__text': true,
'select-option__text-active': value === item.value,
})}
>
{option.label}
{item.label}
</Text>
</TouchableOpacity>
)
})}
}
return (
<BottomModal contentHeight={contentHeight} visible={visible} onClose={onClose} action={action}>
{!!loading ? (
<View style={g(styles, 'loading')}>
<ActivityIndicator size="small" />
<Text style={g(styles, 'loading-text')}>加载中</Text>
</View>
</ScrollView>
) : (
<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>
)
}
......@@ -41,6 +41,7 @@ const getText = (item, val) => {
export default class Select extends Component<IProps> {
state = {
visible: false,
loading: false,
}
constructor(props) {
......@@ -55,7 +56,8 @@ export default class Select extends Component<IProps> {
componentWillReceiveProps(nextProps, nextState) {
const { item, value } = nextProps
const { visible } = this.state
const { visible, loading } = this.state
// 当前只有一个选项时,赋值第一个选项作为当前选项值
if (item && item.options && item.options.length === 1 && item.options[0].value !== value) {
this.onChange(item.options[0].value)
......@@ -64,6 +66,31 @@ export default class Select extends Component<IProps> {
if (isNotBlank(value) && isBlank(val)) {
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)
}
})
}
}
/**
......@@ -81,13 +108,14 @@ export default class Select extends Component<IProps> {
}
}
}
if (isBlank(item.options)) return show(`没有可选择的${item.label}`)
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}
......
......@@ -18,6 +18,7 @@
position absolute
width 100%
max-height 300px
min-height: 100px
background-color foundation_color
bottom 0
border-top-left-radius 5px
......
@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
......@@ -9,22 +9,72 @@
*
*/
import React, { Component } from 'react'
import { View, Text, ScrollView, SafeAreaView } from 'react-native'
import { View, Text, ScrollView, Image, TextInput, FlatList } from 'react-native'
import { inject, observer } from 'mobx-react'
import { IFormField } from 'bonehouse'
import { IFormField, ISurgeryCollectLine } from 'bonehouse'
import * as R from 'ramda'
import Checkbox from '../../components/common/checkbox'
import Select from './select'
import Input from './input'
import Header from '../../components/header/header'
import { g } from '../../utils/utils'
import { g, isBlank } from '../../utils/utils'
import styles from './consumables.styl'
type IProps = {
consumeStore: {
orderId: string
getOrderLines: Function
orderLines: ISurgeryCollectLine[]
}
}
class Consumables extends Component<IProps> {
type IState = {
loading: boolean
lines: ISurgeryCollectLine[]
}
class Consumables extends Component<IProps, IState> {
state = {
loading: false,
lines: [],
mainColumns: [
{
label: '物料名称',
field: 'itemName',
},
{
label: '通用名称',
field: 'generalName',
},
{
label: '规格型号',
field: 'specification',
},
],
subColumns: [
{
label: '序列号',
field: 'serialNumber',
},
{
label: '生产批号',
field: 'productionBatchNumber',
},
{
label: '生产序号',
field: 'productionSerialNumber',
},
{
label: '生产日期',
field: 'productionDate',
},
{
label: '过期日期',
field: 'expirationDate',
},
],
}
constructor(props: IProps) {
super(props)
}
......@@ -38,14 +88,91 @@ class Consumables extends Component<IProps> {
* @param {*}
* @return {*}
*/
getOrderLines() {
console.log(this.props.navigation)
async getOrderLines() {
const { orderId } = this.props.navigation.state.params
let orderLines = this.props.consumeStore.orderLines(orderId)
if (isBlank(orderLines)) {
this.setState({ loading: true })
await this.props.consumeStore.getOrderLines(orderId)
orderLines = this.props.consumeStore.orderLines(orderId)
this.setState({ loading: false })
}
this.setState({ lines: orderLines })
}
/**
* @description: 列表单项渲染
* @param {*} item
* @return {*}
*/
_renderItem({ item }: { item: ISurgeryCollectLine }) {
const { mainColumns, subColumns } = this.state
return (
<View style={g(styles, 'list-item')}>
<Checkbox checked={false} />
<View style={g(styles, 'list-item__info')}>
<View style={g(styles, 'list-item__info-main')}>
<Text>{item.manufacturerProductCode || '无厂家产品代码'}</Text>
{mainColumns.map(col => {
return (
<View style={g(styles, 'info-item')} key={col.field}>
<Text>{col.label}</Text>
<Text>{R.propOr('无', col.field, item)}</Text>
</View>
)
})}
</View>
<View style={g(styles, 'list-item__info-main')}>
{subColumns.map(col => {
return (
<View style={g(styles, 'info-item')} key={col.field}>
<Text>{col.label}</Text>
<Text>{R.propOr('无', col.field, item)}</Text>
</View>
)
})}
</View>
</View>
</View>
)
}
render() {
const { lines } = this.state
return (
<View style={g(styles, 'container')}>
<Header title="消耗确认 - 消耗明细" />
<Header
title="消耗确认 - 消耗明细"
backCallback={() => {
this.props.navigation.goBack()
}}
/>
{/* 搜索框 */}
<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>
{/* 借货单行列表 */}
<FlatList
renderItem={this._renderItem.bind(this)}
data={lines}
keyExtractor={(item, index) => item.itemCode + index}
style={g(styles, 'list')}
/>
</View>
)
}
......
......@@ -47,6 +47,7 @@ type IProps = {
getOrders: Function
orderFollower: Function
orderDoctor: Function
getOrderLines: Function
}
}
......@@ -100,6 +101,7 @@ class Consume extends Component<IProps> {
label: '订单信息',
type: FieldType.SELECT,
options: [],
loading: false,
placeholder: '请选择',
rules: [{ required: true, message: '请选择订单' }],
refrence: ['orgCode', 'customerCode'],
......@@ -303,12 +305,14 @@ class Consume extends Component<IProps> {
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)
}
const item = getFormItem(formItems, 'departmentCode')
item.options = departments
this.setState({ formItems })
}
......@@ -320,11 +324,13 @@ class Consume extends Component<IProps> {
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)
}
const item = getFormItem(formItems, 'customerCode')
item.options = customers
this.setState({ formItems })
}
......@@ -337,17 +343,19 @@ class Consume extends Component<IProps> {
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)
}
const item = getFormItem(formItems, 'surgeryCollectNumber')
item.options = orders
this.setState({ formItems })
}
......@@ -359,6 +367,7 @@ class Consume extends Component<IProps> {
*/
async setSurgeryCollectNumberCallback() {
const { data, formItems } = this.state
let followers = this.props.orgStore.followers(
data.sellerCode,
data.orgCode,
......@@ -395,6 +404,8 @@ class Consume extends Component<IProps> {
this.setState({ data })
})
}
this.props.consumeStore.getOrderLines(data.surgeryCollectNumber)
}
/**
......
......@@ -5,8 +5,6 @@
* @Vision: 1.0
* @Description: 网络服务
*
* @Revision:
*
*/
import { request } from './request'
import { injectable } from 'inversify'
......@@ -66,7 +64,7 @@ export default class Service {
* @param {*}
* @return {*}
*/
getOrders(data: {
getCollectOrders(data: {
orgCode: string
sellerCode: string
customerCode: string
......@@ -74,4 +72,13 @@ export default class Service {
}) {
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 })
}
}
......@@ -10,7 +10,7 @@
*
*/
import { observable, flow, runInAction, action } from 'mobx'
import { observable, flow, runInAction, action, computed } from 'mobx'
import { ISurgeryCollectHeader, ISurgeryCollectLine } from 'bonehouse'
import { injectable, inject } from 'inversify'
import * as R from 'ramda'
......@@ -38,7 +38,7 @@ export default class Consume {
orders(sellerCode: string, orgCode: string, customerCode: string) {
const orders = this._orders[`${sellerCode}_${orgCode}_${customerCode}`] || []
function add() {
function concat() {
return R.reduce((prev: string, next: string) => {
return prev + next + '-'
}, '')(arguments)
......@@ -48,7 +48,7 @@ export default class Consume {
R.applySpec({
label: R.compose(
R.init,
R.converge(add, [
R.converge(concat, [
R.prop('collectNumber'),
R.propOr('无', 'surgeryName'),
R.propOr('无', 'doctorName'),
......@@ -91,12 +91,21 @@ export default class Consume {
}
/**
* @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.getOrders(params) as any
const res = yield this.service.getCollectOrders(params) as any
const { sellerCode, orgCode, customerCode } = params
this._orders[`${sellerCode}_${orgCode}_${customerCode}`] = res.data.surgeryCollectHeaders
})
......@@ -106,5 +115,14 @@ export default class Consume {
* @param {string} surggerCollectNumber
* @return {*}
*/
getOrderLines = flow(function* (this: Consume, surggerCollectNumber: string) {})
getOrderLines = flow(function* (this: Consume, surgeryCollectNumber: string) {
const res = yield this.service.getCollectOrderLines({
surgeryCollectNumber,
filterNoneFlag: 'Y',
})
this._orderLines[surgeryCollectNumber] = R.compose(
R.filter(R.propEq('raisedConsume', 'Y')),
R.pathOr([], ['data', 'lines']),
)(res)
})
}
......@@ -49,6 +49,7 @@ declare module 'bonehouse' {
type: EnumType
dateMode: 'date' | 'datetime'
options?: IOption[]
loading?: boolean
arrow?: boolean
placeholder?: string
rules?: IRule[]
......@@ -150,6 +151,32 @@ declare module 'bonehouse' {
}
export type ISurgeryCollectLine = {
basePrice: number
collectedDate: string
collectedQuantity: number
expirationDate: string
generalName: string
invCode: string
invName: string
itemCode: string
itemName: string
lineNumber: string
manufactureItemCode: string
manufacturerProductCode: string
productionBatchNumber: string
productionDate: string
productionSerialNumber: string
raisedConsume: string
regNumber: string
salePrice: number
serialNumber: string
serialNumberV: string
specification: string
subinvCode: string
subinvName: string
supplierLotNumber: string
supplierSerialNumber: string
surCollectLineNumber: string
surgeryCollectNumber: string
}
}
......@@ -5001,10 +5001,10 @@ mobx-react@~6.0.0:
dependencies:
mobx-react-lite "1.4.0"
mobx@^5.7.0:
version "5.15.7"
resolved "https://registry.npm.taobao.org/mobx/download/mobx-5.15.7.tgz?cache=0&sync_timestamp=1618063126574&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmobx%2Fdownload%2Fmobx-5.15.7.tgz#b9a5f2b6251f5d96980d13c78e9b5d8d4ce22665"
integrity sha1-uaXytiUfXZaYDRPHjptdjUziJmU=
mobx@^4.4:
version "4.15.7"
resolved "https://registry.nlark.com/mobx/download/mobx-4.15.7.tgz?cache=0&sync_timestamp=1619171408362&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fmobx%2Fdownload%2Fmobx-4.15.7.tgz#933281268c3b4658b6cf2526e872cf78ea48ab95"
integrity sha1-kzKBJow7Rli2zyUm6HLPeOpIq5U=
moment@2.29.1, moment@^2.22.1:
version "2.29.1"
......
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