VehicleDetail.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  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. utils.logEventTracking("file_upload: " + res.data.picturePath)
  133. toastShort($t('common.uploadSuccess'));
  134. } else {
  135. toastShort($t('common.uploadFailed'));
  136. }
  137. }).catch(err => {
  138. toastShort(err);
  139. });
  140. }
  141. }).catch(err1 => {
  142. //console.log(err1);
  143. });
  144. }
  145. validate() {
  146. if (!this.state.vehicleInfo.brand) {
  147. toastShort($t('profile.msgSelectBrand'));
  148. return;
  149. }
  150. if (!this.state.vehicleInfo.vehicleModelId) {
  151. toastShort($t('profile.msgSelectModel'));
  152. return;
  153. }
  154. if (!this.state.vehicleInfo.licensePlate) {
  155. if (app.vehicle.showLicencePlate) {
  156. toastShort($t('profile.msgInputPlate'));
  157. } else {
  158. toastShort($t('profile.msgInputCarNo'));
  159. }
  160. return;
  161. }
  162. /*if (!this.state.vehicleInfo.batteryCapacity) {
  163. toastShort($t('profile.msgInputBatCap'));
  164. return;
  165. }
  166. if (!this.state.vehicleInfo.connectorType) {
  167. toastShort($t('profile.msgSelectType'));
  168. return;
  169. }
  170. if (!this.state.vehicleInfo.vehiclePhoto) {
  171. toastShort($t('profile.msgVehiclePhoto'));
  172. return;
  173. }*/
  174. //console.log("车辆信息", this.state.vehicleInfo);
  175. if (this.state.isEdit) {
  176. this.updateVehicle(this.state.vehicleInfo)
  177. } else {
  178. this.addVehicle(this.state.vehicleInfo)
  179. }
  180. }
  181. addVehicle(params) {
  182. Dialog.showProgressDialog();
  183. apiUser.addVehicle(params).then(res => {
  184. Dialog.dismissLoading();
  185. toastShort($t('common.addSuccess'));
  186. goBack();
  187. }).catch((err) => {
  188. Dialog.dismissLoading();
  189. toastShort(err);
  190. });
  191. }
  192. updateVehicle(params) {
  193. Dialog.showProgressDialog();
  194. apiUser.updateVehicle(params).then(res => {
  195. Dialog.dismissLoading();
  196. toastShort($t('common.updateSuccess'));
  197. goBack();
  198. }).catch((err) => {
  199. Dialog.dismissLoading();
  200. toastShort(err);
  201. });
  202. }
  203. getAsterisk() {
  204. if (app.vehicle.showRequiredAsterisk) {
  205. return " *";
  206. } else {
  207. return "";
  208. }
  209. }
  210. render() {
  211. return (
  212. <ScrollView
  213. style={styles.container}
  214. contentContainerStyle={$padding(16)}>
  215. <View style={ui.flexc}>
  216. <MaterialCommunityIcons
  217. name="form-dropdown"
  218. size={20}
  219. color={textPrimary}
  220. style={ui.bold}
  221. />
  222. <TextView style={styles.titleText}>{$t('profile.vehicleBrand')}</TextView>
  223. </View>
  224. <Dropdown
  225. style={styles.formDropdown}
  226. list={this.state.brandOptions}
  227. placeholder={$t('profile.selectBrand') + this.getAsterisk()}
  228. title={$t('profile.vehicleBrand')}
  229. value={this.state.vehicleInfo.brand}
  230. autoSelect={false}
  231. onChange={value => {
  232. this.changeForm("brand", value);
  233. this.getModelOptions();
  234. }}
  235. />
  236. <Dropdown
  237. style={styles.formDropdown}
  238. list={this.state.modelOptions}
  239. placeholder={$t('profile.selectModel') + this.getAsterisk()}
  240. title={$t('profile.vehicleModel')}
  241. value={this.state.vehicleInfo.vehicleModelId}
  242. valueKey={"vehicleModelId"}
  243. nameKey={"model"}
  244. autoSelect={true}
  245. onChange={value => this.changeForm("vehicleModelId", value)}
  246. />
  247. <TextInput
  248. style={styles.formInput}
  249. defaultValue={this.state.vehicleInfo.licensePlate}
  250. placeholder={$t(app.vehicle.showLicencePlate ? 'profile.enterLicensePlate' : 'profile.enterLicenseNumber') + this.getAsterisk()}
  251. placeholderTextColor={textPlacehoder}
  252. maxLength={20}
  253. onChangeText={text => this.changeForm("licensePlate", text)}
  254. />
  255. <View style={styles.formInputRow}>
  256. <TextInput
  257. style={styles.itemInput}
  258. defaultValue={this.state.vehicleInfo.batteryCapacity}
  259. placeholder={$t('profile.enterBatteryCapacity')}
  260. placeholderTextColor={textPlacehoder}
  261. maxLength={20}
  262. keyboardType='decimal-pad'
  263. onChangeText={text => this.changeForm("batteryCapacity", text)}
  264. />
  265. <TextView style={styles.titleText}>kWh</TextView>
  266. </View>
  267. { app.vehicle.requireConnectorType && <>
  268. <View style={ui.flexc}>
  269. <MaterialCommunityIcons
  270. name="form-dropdown"
  271. size={20}
  272. color={textPrimary}
  273. style={ui.bold}
  274. />
  275. <TextView style={styles.titleText}>{$t('profile.connecterType')}</TextView>
  276. </View>
  277. <Dropdown
  278. style={styles.formDropdown}
  279. list={this.state.typeOptions}
  280. placeholder={$t('profile.selectConnecterType')}
  281. title={$t('profile.connecterType')}
  282. value={this.state.vehicleInfo.connectorType}
  283. onChange={value => this.changeForm("connectorType", value)}
  284. autoSelect={false}
  285. />
  286. </> }
  287. { app.vehicle.requireImageUpload && <>
  288. <View style={ui.flexc}>
  289. <MaterialCommunityIcons
  290. name="tray-arrow-up"
  291. size={20}
  292. color={textPrimary}
  293. style={ui.bold}
  294. />
  295. <TextView style={styles.titleText}>{$t('profile.plsUploadImageCar')}</TextView>
  296. </View>
  297. <View style={styles.uploadGroup}>
  298. { this.state.vehicleInfo.vehiclePhoto
  299. ? <Pressable
  300. onPress={() => this.uploadImage()}>
  301. <Image
  302. style={styles.uploadImage}
  303. source={{uri: utils.getImageUrl(this.state.vehicleInfo.vehiclePhoto)}}
  304. />
  305. </Pressable>
  306. : <Pressable
  307. style={styles.uploadView}
  308. onPress={() => this.uploadImage()}>
  309. <MaterialCommunityIcons
  310. name="tray-arrow-up"
  311. size={32}
  312. color={textCancel}
  313. style={ui.bold}
  314. />
  315. <TextView style={styles.uploadTitle}>{$t('profile.selectUpload')}</TextView>
  316. <TextView style={styles.uploadDesc}>{$t('profile.max4mbPhoto')}</TextView>
  317. </Pressable>
  318. }
  319. </View>
  320. </> }
  321. <View style={styles.buttonView}>
  322. <Button
  323. text={$t('common.save')}
  324. elevation={1.5}
  325. onClick={() => {
  326. this.validate();
  327. }}/>
  328. </View>
  329. </ScrollView>
  330. );
  331. }
  332. }
  333. const styles = StyleSheet.create({
  334. container: {
  335. flex: 1
  336. },
  337. titleText: {
  338. padding: 8,
  339. fontSize: 14,
  340. color: textPrimary,
  341. fontWeight: 'bold'
  342. },
  343. formInput: {
  344. ...$margin(8, 0),
  345. padding: 12,
  346. borderWidth: 1,
  347. borderRadius: 4,
  348. borderStyle: 'solid',
  349. borderColor: "#EAEAEA",
  350. },
  351. formDropdown: {
  352. ...$margin(8, 0),
  353. padding: 12,
  354. borderWidth: 1,
  355. borderRadius: 4,
  356. borderStyle: 'solid',
  357. borderColor: "#EAEAEA",
  358. alignItems: 'center',
  359. flexDirection: 'row'
  360. },
  361. formInputRow: {
  362. ...$margin(8, 0),
  363. padding: 8,
  364. borderWidth: 1,
  365. borderRadius: 4,
  366. borderStyle: 'solid',
  367. borderColor: "#EAEAEA",
  368. alignItems: 'center',
  369. flexDirection: 'row'
  370. },
  371. itemInput: {
  372. flex: 1,
  373. padding: 4
  374. },
  375. uploadView: {
  376. width: 160,
  377. height: 160,
  378. ...$margin(8, 0),
  379. padding: 8,
  380. borderWidth: 1,
  381. borderRadius: 4,
  382. borderStyle: 'solid',
  383. borderColor: "#EAEAEA",
  384. alignItems: 'center',
  385. justifyContent: 'center'
  386. },
  387. uploadImage: {
  388. width: 160,
  389. height: 160,
  390. ...$margin(8, 0)
  391. },
  392. uploadTitle: {
  393. fontSize: 14,
  394. color: textPrimary,
  395. paddingTop: 8
  396. },
  397. uploadDesc: {
  398. fontSize: 12,
  399. color: textCancel,
  400. paddingTop: 2
  401. },
  402. buttonView: {
  403. marginTop: 32,
  404. marginBottom: 8
  405. }
  406. })