VehicleDetail.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. /**
  2. * 添加/编辑 Vehicle页面
  3. * @邠心vbe on 2024/01/30
  4. */
  5. import React, { Component } from 'react';
  6. import { View, Text, StyleSheet, TextInput, Image, Pressable, ScrollView } from 'react-native';
  7. import Dialog from '../../components/Dialog';
  8. import apiUser from '../../api/apiUser';
  9. import TextView from '../../components/TextView';
  10. import Dropdown from '../../components/Dropdown';
  11. import { TypeImageList } from '../chargeV2/Charging';
  12. import ImageCropPicker from 'react-native-image-crop-picker';
  13. import { UploadThemes } from '../../components/ThemesConfig';
  14. import apiUpload from '../../api/apiUpload';
  15. import utils from '../../utils/utils';
  16. import app from '../../../app.json';
  17. const options = {
  18. width: 300,
  19. height: 300,
  20. cropping: true,
  21. multiple: false,
  22. mediaType: 'photo',
  23. writeTempFile: false,
  24. compressImageQuality: 0.8,
  25. compressImageMaxWidth: 720,
  26. compressImageMaxHeight: 1280,
  27. ...UploadThemes
  28. }
  29. export default class VehicleDetail extends Component {
  30. constructor(props) {
  31. super(props);
  32. this.state = {
  33. isEdit: false,
  34. vehicleInfo: {
  35. brand: "",
  36. model: "",
  37. connectorType: ""
  38. },
  39. brandOptions: [],
  40. modelOptions: [],
  41. typeOptions: []
  42. };
  43. }
  44. componentDidMount() {
  45. this.getBrandOptions();
  46. const params = this.props.route.params;
  47. if (params.id) {
  48. this.setState({
  49. isEdit: true
  50. })
  51. Dialog.showProgressDialog();
  52. this.getVehicleData(params.id);
  53. }
  54. }
  55. getBrandOptions() {
  56. apiUser.getVehicleBrandList().then(res => {
  57. if (res.data) {
  58. this.setState({
  59. brandOptions: res.data
  60. })
  61. }
  62. }).catch((err) => {
  63. Dialog.dismissLoading();
  64. toastShort(err)
  65. });
  66. const types = []
  67. TypeImageList.forEach((item, index) => {
  68. types.push(item.name);
  69. })
  70. this.setState({
  71. typeOptions: types
  72. })
  73. }
  74. getModelOptions() {
  75. if (this.state.vehicleInfo.brand) {
  76. apiUser.getVehicleModelByBrand({
  77. brand: this.state.vehicleInfo.brand
  78. }).then(res => {
  79. if (res.data) {
  80. this.setState({
  81. modelOptions: res.data
  82. })
  83. }
  84. }).catch((err) => {
  85. toastShort(err)
  86. this.setState({
  87. modelOptions: []
  88. })
  89. });
  90. } else {
  91. this.setState({
  92. modelOptions: []
  93. })
  94. }
  95. }
  96. getVehicleData(id) {
  97. apiUser.getVehicleById({
  98. vehiclePk: id
  99. }).then(res => {
  100. Dialog.dismissLoading();
  101. if (res.data) {
  102. const info = res.data;
  103. this.setState({
  104. vehicleInfo: info
  105. }, () => {
  106. this.getModelOptions();
  107. });
  108. }
  109. }).catch((err) => {
  110. Dialog.dismissLoading();
  111. toastShort(err)
  112. });
  113. }
  114. changeForm(key, value) {
  115. const form = {
  116. ...this.state.vehicleInfo
  117. }
  118. form[key] = value;
  119. this.setState({
  120. vehicleInfo: form
  121. })
  122. }
  123. uploadImage() {
  124. ImageCropPicker.openPicker({
  125. ...options,
  126. cropperToolbarTitle: $t('common.cropperTitle')
  127. }).then(image => {
  128. if (image.path) {
  129. apiUpload.uploadImage(image.path, image.mime, 'PDVL').then(res => {
  130. if (res.success && res.data.picturePath) {
  131. this.changeForm("vehiclePhoto", res.data.picturePath)
  132. toastShort($t('common.uploadSuccess'));
  133. } else {
  134. toastShort($t('common.uploadFailed'));
  135. }
  136. }).catch(err => {
  137. toastShort(err);
  138. });
  139. }
  140. }).catch(err1 => {
  141. //console.log(err1);
  142. });
  143. }
  144. validate() {
  145. if (!this.state.vehicleInfo.brand) {
  146. toastShort($t('profile.msgSelectBrand'));
  147. return;
  148. }
  149. if (!this.state.vehicleInfo.vehicleModelId) {
  150. toastShort($t('profile.msgSelectModel'));
  151. return;
  152. }
  153. if (!this.state.vehicleInfo.licensePlate) {
  154. if (app.vehicle.showLicencePlate) {
  155. toastShort($t('profile.msgInputPlate'));
  156. } else {
  157. toastShort($t('profile.msgInputCarNo'));
  158. }
  159. return;
  160. }
  161. /*if (!this.state.vehicleInfo.batteryCapacity) {
  162. toastShort($t('profile.msgInputBatCap'));
  163. return;
  164. }
  165. if (!this.state.vehicleInfo.connectorType) {
  166. toastShort($t('profile.msgSelectType'));
  167. return;
  168. }
  169. if (!this.state.vehicleInfo.vehiclePhoto) {
  170. toastShort($t('profile.msgVehiclePhoto'));
  171. return;
  172. }*/
  173. //console.log("车辆信息", this.state.vehicleInfo);
  174. if (this.state.isEdit) {
  175. this.updateVehicle(this.state.vehicleInfo)
  176. } else {
  177. this.addVehicle(this.state.vehicleInfo)
  178. }
  179. }
  180. addVehicle(params) {
  181. Dialog.showProgressDialog();
  182. apiUser.addVehicle(params).then(res => {
  183. Dialog.dismissLoading();
  184. toastShort($t('common.addSuccess'));
  185. goBack();
  186. }).catch((err) => {
  187. Dialog.dismissLoading();
  188. toastShort(err);
  189. });
  190. }
  191. updateVehicle(params) {
  192. Dialog.showProgressDialog();
  193. apiUser.updateVehicle(params).then(res => {
  194. Dialog.dismissLoading();
  195. toastShort($t('common.updateSuccess'));
  196. goBack();
  197. }).catch((err) => {
  198. Dialog.dismissLoading();
  199. toastShort(err);
  200. });
  201. }
  202. getAsterisk() {
  203. if (app.vehicle.showRequiredAsterisk) {
  204. return " *";
  205. } else {
  206. return "";
  207. }
  208. }
  209. render() {
  210. return (
  211. <ScrollView
  212. style={styles.container}
  213. contentContainerStyle={$padding(16)}>
  214. <View style={ui.flexc}>
  215. <MaterialCommunityIcons
  216. name="form-dropdown"
  217. size={20}
  218. color={textPrimary}
  219. style={ui.bold}
  220. />
  221. <TextView style={styles.titleText}>{$t('profile.vehicleBrand')}</TextView>
  222. </View>
  223. <Dropdown
  224. style={styles.formDropdown}
  225. list={this.state.brandOptions}
  226. placeholder={$t('profile.selectBrand') + this.getAsterisk()}
  227. title={$t('profile.vehicleBrand')}
  228. value={this.state.vehicleInfo.brand}
  229. autoSelect={false}
  230. onChange={value => {
  231. this.changeForm("brand", value);
  232. this.getModelOptions();
  233. }}
  234. />
  235. <Dropdown
  236. style={styles.formDropdown}
  237. list={this.state.modelOptions}
  238. placeholder={$t('profile.selectModel') + this.getAsterisk()}
  239. title={$t('profile.vehicleModel')}
  240. value={this.state.vehicleInfo.vehicleModelId}
  241. valueKey={"vehicleModelId"}
  242. nameKey={"model"}
  243. autoSelect={true}
  244. onChange={value => this.changeForm("vehicleModelId", value)}
  245. />
  246. <TextInput
  247. style={styles.formInput}
  248. defaultValue={this.state.vehicleInfo.licensePlate}
  249. placeholder={$t(app.vehicle.showLicencePlate ? 'profile.enterLicensePlate' : 'profile.enterLicenseNumber') + this.getAsterisk()}
  250. placeholderTextColor={textPlacehoder}
  251. maxLength={20}
  252. onChangeText={text => this.changeForm("licensePlate", text)}
  253. />
  254. <View style={styles.formInputRow}>
  255. <TextInput
  256. style={styles.itemInput}
  257. defaultValue={this.state.vehicleInfo.batteryCapacity}
  258. placeholder={$t('profile.enterBatteryCapacity')}
  259. placeholderTextColor={textPlacehoder}
  260. maxLength={20}
  261. keyboardType='decimal-pad'
  262. onChangeText={text => this.changeForm("batteryCapacity", text)}
  263. />
  264. <TextView style={styles.titleText}>kWh</TextView>
  265. </View>
  266. { app.vehicle.requireConnectorType && <>
  267. <View style={ui.flexc}>
  268. <MaterialCommunityIcons
  269. name="form-dropdown"
  270. size={20}
  271. color={textPrimary}
  272. style={ui.bold}
  273. />
  274. <TextView style={styles.titleText}>{$t('profile.connecterType')}</TextView>
  275. </View>
  276. <Dropdown
  277. style={styles.formDropdown}
  278. list={this.state.typeOptions}
  279. placeholder={$t('profile.selectConnecterType')}
  280. title={$t('profile.connecterType')}
  281. value={this.state.vehicleInfo.connectorType}
  282. onChange={value => this.changeForm("connectorType", value)}
  283. autoSelect={false}
  284. />
  285. </> }
  286. { app.vehicle.requireImageUpload && <>
  287. <View style={ui.flexc}>
  288. <MaterialCommunityIcons
  289. name="tray-arrow-up"
  290. size={20}
  291. color={textPrimary}
  292. style={ui.bold}
  293. />
  294. <TextView style={styles.titleText}>{$t('profile.plsUploadImageCar')}</TextView>
  295. </View>
  296. <View style={styles.uploadGroup}>
  297. { this.state.vehicleInfo.vehiclePhoto
  298. ? <Pressable
  299. onPress={() => this.uploadImage()}>
  300. <Image
  301. style={styles.uploadImage}
  302. source={{uri: utils.getImageUrl(this.state.vehicleInfo.vehiclePhoto)}}
  303. />
  304. </Pressable>
  305. : <Pressable
  306. style={styles.uploadView}
  307. onPress={() => this.uploadImage()}>
  308. <MaterialCommunityIcons
  309. name="tray-arrow-up"
  310. size={32}
  311. color={textCancel}
  312. style={ui.bold}
  313. />
  314. <TextView style={styles.uploadTitle}>{$t('profile.selectUpload')}</TextView>
  315. <TextView style={styles.uploadDesc}>{$t('profile.max4mbPhoto')}</TextView>
  316. </Pressable>
  317. }
  318. </View>
  319. </> }
  320. <View style={styles.buttonView}>
  321. <Button
  322. text={$t('common.save')}
  323. elevation={1.5}
  324. onClick={() => {
  325. this.validate();
  326. }}/>
  327. </View>
  328. </ScrollView>
  329. );
  330. }
  331. }
  332. const styles = StyleSheet.create({
  333. container: {
  334. flex: 1
  335. },
  336. titleText: {
  337. padding: 8,
  338. fontSize: 14,
  339. color: textPrimary,
  340. fontWeight: 'bold'
  341. },
  342. formInput: {
  343. ...$margin(8, 0),
  344. padding: 12,
  345. borderWidth: 1,
  346. borderRadius: 4,
  347. borderStyle: 'solid',
  348. borderColor: "#EAEAEA",
  349. },
  350. formDropdown: {
  351. ...$margin(8, 0),
  352. padding: 12,
  353. borderWidth: 1,
  354. borderRadius: 4,
  355. borderStyle: 'solid',
  356. borderColor: "#EAEAEA",
  357. alignItems: 'center',
  358. flexDirection: 'row'
  359. },
  360. formInputRow: {
  361. ...$margin(8, 0),
  362. padding: 8,
  363. borderWidth: 1,
  364. borderRadius: 4,
  365. borderStyle: 'solid',
  366. borderColor: "#EAEAEA",
  367. alignItems: 'center',
  368. flexDirection: 'row'
  369. },
  370. itemInput: {
  371. flex: 1,
  372. padding: 4
  373. },
  374. uploadView: {
  375. width: 160,
  376. height: 160,
  377. ...$margin(8, 0),
  378. padding: 8,
  379. borderWidth: 1,
  380. borderRadius: 4,
  381. borderStyle: 'solid',
  382. borderColor: "#EAEAEA",
  383. alignItems: 'center',
  384. justifyContent: 'center'
  385. },
  386. uploadImage: {
  387. width: 160,
  388. height: 160,
  389. ...$margin(8, 0)
  390. },
  391. uploadTitle: {
  392. fontSize: 14,
  393. color: textPrimary,
  394. paddingTop: 8
  395. },
  396. uploadDesc: {
  397. fontSize: 12,
  398. color: textCancel,
  399. paddingTop: 2
  400. },
  401. buttonView: {
  402. marginTop: 32,
  403. marginBottom: 8
  404. }
  405. })