index.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. import React, { Fragment, useState, useEffect, useCallback, createRef, useRef } from 'react';
  2. import { View, Text, Alert, FlatList, StyleSheet, TouchableOpacity } from 'react-native';
  3. import Styled from 'styled-components/native';
  4. import {
  5. Search,
  6. SearchIcon,
  7. Line,
  8. TextInput,
  9. checkFilter,
  10. filterValue,
  11. ListStyle,
  12. DetailIcon,
  13. RightArrow,
  14. CreateButton,
  15. SearchBoxIcon,
  16. DefaultButton,
  17. PrimaryButton,
  18. SearchTitle,
  19. } from '~/Components/Listing/Search';
  20. import Checkbox from '~/Components/UIControls/Checkbox';
  21. import Theme from '~/Themes';
  22. import BottomTabBarLayout from '~/Components/Layouts/BottomTabBarLayout';
  23. import session from '~/Utils/session';
  24. import SearchList, { SearchListContainer } from '~/Components/Listing/SearchList';
  25. import EmptyView from '~/Components/Listing/EmptyView';
  26. import EntitySelect from '~/Components/EntitySelect';
  27. import { useToast } from '~/Components/UIControls/Message';
  28. import { DateTimePicker } from '~/Components/UIControls/DateTimePicker';
  29. import Input from '~/Components/UIControls/Input';
  30. import Form from '~/Components/Form';
  31. import { Util } from '~/Utils/utils';
  32. import { useAuth } from '~/Components/Hooks';
  33. import { Selectbox } from '~/Components/UIControls/Selectbox';
  34. import { useLayoutAction, PopupLayout } from '~/Components/Layouts/PopupLayout';
  35. const style = StyleSheet.create({
  36. container: { flexDirection: 'column' },
  37. header: { padding: 15, flexDirection: 'row', alignItems: 'flex-start', justifyContent: 'center' },
  38. headerBadge: {
  39. width: 63,
  40. height: 35,
  41. borderRadius: 63,
  42. borderStyle: 'solid',
  43. borderWidth: 1,
  44. borderColor: '#0b83e6',
  45. alignItems: 'center',
  46. justifyContent: 'center',
  47. },
  48. headerBadgeText: { color: '#0b83e6', fontSize: 14, textAlign: 'center' },
  49. headerCategory: { fontSize: 16, color: '#9aa3ac' },
  50. headerName: { fontSize: 16, color: '#000' },
  51. headerDetail: { marginLeft: 15, flexDirection: 'column', flex: 1 },
  52. headerExtraContainer: { flexDirection: 'row' },
  53. headerExtra: { color: '#b9bac4', fontSize: 14 },
  54. stock: { paddingHorizontal: 15, paddingVertical: 8, backgroundColor: '#f8fcff', flexDirection: 'row' },
  55. stockLabel: { color: '#9aa3ac', fontSize: 16, fontFamily: Theme.Fonts.Regular },
  56. stockValue: { fontWeight: '500', fontSize: 16, fontFamily: Theme.Fonts.Regular },
  57. });
  58. // list item
  59. class Item extends React.PureComponent {
  60. render() {
  61. const { item, index, onPress = () => {} } = this.props;
  62. const zebra = index % 2 == 0 ? true : false;
  63. return (
  64. <TouchableOpacity
  65. onPress={onPress}
  66. style={{
  67. marginBottom: 10,
  68. borderTopWidth: 1,
  69. borderTopColor: '#e9e9e9',
  70. backgroundColor: zebra ? '#fdfdfd' : '#fff',
  71. }}
  72. >
  73. <View style={style.container}>
  74. <View style={style.header}>
  75. <View style={style.headerBadge}>
  76. <Text style={style.headerBadgeText}>{item.BusinessFieldName}</Text>
  77. </View>
  78. <View style={style.headerDetail}>
  79. <Text style={style.headerCategory}>{item.ProgressName}</Text>
  80. <Text style={style.headerName}>{item.Title}</Text>
  81. <View style={style.headerExtraContainer}>
  82. <Text style={{ ...style.headerExtra, marginRight: 'auto' }}>{item.OrderUserName}</Text>
  83. <Text style={{ ...style.headerExtra, marginLeft: 'auto' }}>
  84. {Util.toDateString(item.OrderDate, '', '.')}
  85. </Text>
  86. </View>
  87. </View>
  88. </View>
  89. <View style={style.stock} style={{ display: 'none' }}>
  90. <Text style={{ ...style.stockLabel, marginRight: 9 }}>승인자</Text>
  91. <Text style={{ ...style.stockValue, marginRight: 'auto' }}>{item.ApprovalUserName}</Text>
  92. <Text style={{ ...style.stockLabel, marginLeft: 'auto' }}>승인일</Text>
  93. <Text style={{ ...style.stockValue, marginLeft: 9 }}>{Util.toDateString(item.ApprovalDate)}</Text>
  94. </View>
  95. </View>
  96. </TouchableOpacity>
  97. );
  98. }
  99. }
  100. // list and search
  101. export default Popup = ({ siteId = 0, userinfo, auth, popup = DefaultAction }) => {
  102. const [filters, setFilters] = useState({
  103. 'FmsMaterialPurchaseRequest.ProgressId_eq': { field: 'FmsMaterialPurchaseRequest.ProgressId', op: 'eq', value: '3' },
  104. });
  105. const [list, setList] = useState(null);
  106. const [page, setPage] = useState(1);
  107. const [refreshing, setRefreshing] = useState(false);
  108. const pages = useRef(10);
  109. const { showMessage } = useToast();
  110. const [searchForm, setSearchForm] = useState({
  111. FirstClassId: '',
  112. SecondClassId: '',
  113. ThirdClassId: '',
  114. BusinessFieldId: '',
  115. });
  116. const isUseItems = useRef([
  117. { label: '사용', value: true },
  118. { label: '미사용', value: false },
  119. ]);
  120. const apiUrl = `api/MaterialPurchaseOrder?siteId=${userinfo.SiteId}&businessAuth=${auth.Business}&progressId=3`;
  121. // search events...
  122. const start = () => {
  123. setRefreshing(true);
  124. };
  125. const success = (data, append) => {
  126. pages.current = data.pages;
  127. //console.log(data);
  128. if (append && page > 1) {
  129. setList(list.concat(data.list));
  130. } else {
  131. setList(data.list);
  132. }
  133. setRefreshing(false);
  134. };
  135. const fail = (e) => {
  136. showMessage(e.message);
  137. setRefreshing(false);
  138. };
  139. const refreshList = () => {
  140. setPage('refresh-' + Math.random());
  141. };
  142. const actionHandler = (action, parameter = {}) => {
  143. const actions = {
  144. close: () => {
  145. console.log('close...');
  146. popup.close();
  147. },
  148. addSelected: () => {
  149. popup.select([]);
  150. },
  151. };
  152. actions[action]();
  153. };
  154. return (
  155. <PopupLayout title="발주등록선택" header={Header} actionHandler={actionHandler}>
  156. <SearchListContainer>
  157. <SearchList
  158. page={page}
  159. pages={pages.current}
  160. setPage={setPage}
  161. refreshing={refreshing}
  162. data={list}
  163. style={{ backgroundColor: '#f5f5f5' }}
  164. renderItem={({ item, index }) => {
  165. return (
  166. <Item
  167. item={item}
  168. index={index}
  169. onPress={() => {
  170. popup.select(item);
  171. }}
  172. />
  173. );
  174. }}
  175. ListEmptyComponent={<EmptyView list={list} />}
  176. />
  177. </SearchListContainer>
  178. <Search
  179. id="material-popup"
  180. api={apiUrl}
  181. page={page}
  182. setPage={setPage}
  183. limit={50}
  184. filters={filters}
  185. sort={{ field: 'OrderDate', order: 'desc' }}
  186. onStart={start}
  187. onSuccess={success}
  188. onFailure={fail}
  189. >
  190. <>
  191. <SearchTitle title="업무분야" />
  192. <EntitySelect
  193. style={{ marginBottom: 20 }}
  194. entity="CmBusinessField"
  195. defaultLabel="업무분야"
  196. useCheck={true}
  197. auth={auth}
  198. onChange={(item) => {
  199. setSearchForm({
  200. ...searchForm,
  201. BusinessFieldId: item.value,
  202. });
  203. filterValue([filters, setFilters], 'Material.BusinessFieldId', item.value, 'eq');
  204. }}
  205. auth={auth}
  206. />
  207. <SearchTitle title="진행상태" />
  208. <EntitySelect
  209. style={{ marginBottom: 20 }}
  210. entity="FmsMaterialCodeProgress"
  211. id="ProgressId"
  212. defaultLabel="진행상태"
  213. onChange={(item) => {
  214. filterValue([filters, setFilters], 'ProgressId', item.value, 'eq');
  215. }}
  216. />
  217. <SearchTitle title="제목" />
  218. <Input
  219. style={{ marginBottom: 20 }}
  220. placeholder="제목"
  221. small
  222. onChangeText={(value) => filterValue([filters, setFilters], 'Title', value, 'cn')}
  223. />
  224. <SearchTitle title="자재명" />
  225. <Input
  226. style={{ marginBottom: 20 }}
  227. placeholder="자재명"
  228. small
  229. onChangeText={(value) => filterValue([filters, setFilters], 'Material.Name', value, 'cn')}
  230. />
  231. <SearchTitle title="신청일" />
  232. <DateTimePicker
  233. style={{ marginBottom: 5 }}
  234. placeholder="부터"
  235. useClear={true}
  236. onChange={(newDate) => {
  237. filterValue([filters, setFilters], 'RequestDate', Util.toDateString(newDate), 'ge');
  238. }}
  239. />
  240. <DateTimePicker
  241. style={{ marginBottom: 20 }}
  242. placeholder="까지"
  243. useClear={true}
  244. onChange={(newDate) => {
  245. filterValue([filters, setFilters], 'RequestDate', Util.toDateString(newDate), 'le');
  246. }}
  247. />
  248. <SearchTitle title="규격" />
  249. <Input
  250. style={{ marginBottom: 20 }}
  251. placeholder="규격"
  252. small
  253. onChangeText={(value) => filterValue([filters, setFilters], 'Material.Standard', value, 'cn')}
  254. />
  255. </>
  256. </Search>
  257. </PopupLayout>
  258. );
  259. };
  260. const Header = () => {
  261. const { callAction } = useLayoutAction();
  262. return (
  263. <Fragment>
  264. {/**
  265. <PrimaryButton
  266. onPress={() => {
  267. callAction('addSelected');
  268. }}
  269. >
  270. 선택추가
  271. </PrimaryButton>
  272. **/}
  273. <DefaultButton
  274. onPress={() => {
  275. callAction('close');
  276. }}
  277. >
  278. 닫기
  279. </DefaultButton>
  280. <SearchBoxIcon style={{ marginLeft: 5 }} id="material-popup" />
  281. </Fragment>
  282. );
  283. };