GoodsDetailScreen.jsx 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472
  1. import * as WebBrowser from "expo-web-browser";
  2. import * as React from "react";
  3. import { Dimensions } from "react-native";
  4. import { Button } from "@ui-kitten/components";
  5. import { Div, Image, Text, Avatar, Input, Icon } from "react-native-magnus";
  6. import { ScrollView } from "react-native-gesture-handler";
  7. import { useFocusEffect } from "@react-navigation/native";
  8. import { useModel } from "flooks";
  9. import { useMount, useCreation, useRequest } from "ahooks";
  10. import UpLoadImage from "../../components/UpLoadImage";
  11. import OpenTime from "../../components/OpenTime";
  12. import CommentCard from "../../components/Comment";
  13. const { width } = Dimensions.get("window");
  14. const img1 = require("../../assets/images/zan.png");
  15. const img2 = require("../../assets/images/cai.png");
  16. const AppraisalSortMap = new Map([
  17. [
  18. "ALL",
  19. {
  20. name: "全部",
  21. },
  22. ],
  23. [
  24. "LATEST",
  25. {
  26. name: "最新",
  27. },
  28. ],
  29. [
  30. "PRAISE",
  31. {
  32. name: "好评",
  33. },
  34. ],
  35. [
  36. "BAD_REVIEW",
  37. {
  38. name: "差评",
  39. isBad: true,
  40. },
  41. ],
  42. [
  43. "HAVE_PIC",
  44. {
  45. name: "有图",
  46. },
  47. ],
  48. ]);
  49. const CommentItem = ({ info }) => {
  50. const imgs = info.img ? info.img.split(",") : [];
  51. const imageSize = imgs.length > 1 ? 80 : 167;
  52. return (
  53. <Div row py={10} px={15} bg="white" mt={10}>
  54. <Image source={{ uri: info.avatar }} w={33} h={33} />
  55. <Div flex={1} ml={5}>
  56. <Div row>
  57. <Div flex={1}>
  58. <Text fontSize="sm" textAlign="left">
  59. {info.nickname}
  60. </Text>
  61. <Div row>
  62. <Image source={img1} w={12} h={12} />
  63. <Text fontSize="sm" color="yellow500" textAlign="left">
  64. {info.likes || 0}
  65. </Text>
  66. </Div>
  67. </Div>
  68. <Text fontSize="sm" color="gray400" textAlign="left">
  69. {info.appraiseTime}
  70. </Text>
  71. </Div>
  72. <Text my={5} textAlign="left">
  73. {info.goodsAppraise}
  74. </Text>
  75. <Div row>
  76. {imgs.map((item, index) => {
  77. return (
  78. <Image
  79. key={index}
  80. mt={5}
  81. mr={5}
  82. source={{ uri: item }}
  83. w={imageSize}
  84. h={imageSize}
  85. rounded={3}
  86. />
  87. );
  88. })}
  89. </Div>
  90. </Div>
  91. </Div>
  92. );
  93. };
  94. export default function LinksScreen({ navigation, route }) {
  95. const { changeBackground } = useModel("barModel");
  96. const { httpGet, httpPost } = useModel("httpModel");
  97. const { success, loading, clearLoading } = useModel("loadingModel", true);
  98. useFocusEffect(
  99. React.useCallback(() => {
  100. changeBackground("rgba(0,0,0,0)");
  101. }, [])
  102. );
  103. const {
  104. addClassification,
  105. editGoodsMap,
  106. saveClassByList,
  107. removeGoodsClassMap,
  108. sortClassification,
  109. } = useModel("goodsModel");
  110. const { GVDYKL, IQYCDU } = useModel("wordsModel");
  111. const { params } = route;
  112. const { goodsId } = params;
  113. const [goodsInfo, setgoodsInfo] = React.useState({});
  114. const [comments, setcomments] = React.useState([]);
  115. const [appraisalSort, setappraisalSort] = React.useState("ALL");
  116. useRequest(
  117. () => {
  118. return httpGet(`/appraisal/goods?goodsId=${goodsId}`)
  119. .then(res => {
  120. return Promise.resolve(res);
  121. })
  122. .catch(e => {
  123. return Promise.resolve([]);
  124. });
  125. },
  126. {
  127. refreshDeps: [goodsId],
  128. onSuccess: result => {
  129. setcomments(result);
  130. },
  131. onError: e => {
  132. setcomments([]);
  133. },
  134. }
  135. );
  136. useMount(() => {
  137. if (goodsId) {
  138. loading();
  139. httpGet(`/goods/get/${goodsId}`, {}, true)
  140. .then(res => {
  141. setgoodsInfo(res);
  142. setname(res.name);
  143. setimg(res.img);
  144. setinventory(res.inventory.toString());
  145. setamount((res.amount || "").toString());
  146. setdiscountAmount((res.discountAmount || "").toString());
  147. setintroduction(res.introduction);
  148. changeGoodsSpecification(sortClassification(res.specifications));
  149. setpackingPrice((res.packingPrice || 0).toString());
  150. changeWeek(res.week || "");
  151. changeStartTime(res.startTime || "");
  152. changeEndTime(res.endTime || "");
  153. })
  154. .finally(() => {
  155. clearLoading();
  156. });
  157. }
  158. });
  159. React.useEffect(() => {
  160. if (editGoodsMap.has(goodsId)) {
  161. changeGoodsSpecification(editGoodsMap.get(goodsId));
  162. }
  163. }, [editGoodsMap.get(goodsId)]);
  164. const { goodNum, badNum, monthSales, merchantId } = goodsInfo;
  165. const [img, setimg] = React.useState();
  166. const [name, setname] = React.useState("");
  167. const [inventory, setinventory] = React.useState(0);
  168. const [amount, setamount] = React.useState("");
  169. const [discountAmount, setdiscountAmount] = React.useState();
  170. const [packingPrice, setpackingPrice] = React.useState("0");
  171. const [introduction, setintroduction] = React.useState("");
  172. const [goodsSpecification, changeGoodsSpecification] = React.useState([]);
  173. const [week, changeWeek] = React.useState("");
  174. const [startTime, changeStartTime] = React.useState("08:00:00");
  175. const [endTime, changeEndTime] = React.useState("18:00:00");
  176. // 需要批量提交的规格
  177. const postByList = useCreation(() => {
  178. return goodsSpecification.filter(item => {
  179. return !item.id || item.id < 0;
  180. });
  181. }, [goodsSpecification]);
  182. return (
  183. <>
  184. {/* <NavHeaderBar title="商品规格编辑" /> */}
  185. <ScrollView
  186. contentContainerStyle={{
  187. flexGrow: 1,
  188. backgroundColor: "#eee",
  189. }}
  190. >
  191. <Div h={width}>
  192. <UpLoadImage value={img} changeIcon={setimg} size="100%" />
  193. </Div>
  194. <Div bg="white" py={20} px={15}>
  195. <Div row>
  196. <Text fontSize="sm" minW={70}>
  197. 商品名
  198. </Text>
  199. <Div flex={1} ml={5} alignItems="flex-start">
  200. <Input
  201. value={name}
  202. h={25}
  203. py={2}
  204. lineHeight={21}
  205. fontSize="md"
  206. bg="gray100"
  207. minW={119}
  208. onChangeText={setname}
  209. />
  210. <Div row alignItems="center" my={10}>
  211. <Image source={img1} w={12} h={12} />
  212. <Text fontSize="xs" mr={10} ml={3} color="yellow500">
  213. {goodNum || 0}
  214. </Text>
  215. <Image source={img2} w={12} h={12} />
  216. <Text fontSize="xs" ml={3} mr={10} color="gray300">
  217. {badNum || 0}
  218. </Text>
  219. <Text fontSize="xs" color="gray300">
  220. 月售
  221. {monthSales || 0}
  222. </Text>
  223. </Div>
  224. </Div>
  225. </Div>
  226. <Div row alignItems="center">
  227. <Text fontSize="sm" minW={70}>
  228. 份数
  229. </Text>
  230. <Input
  231. value={inventory}
  232. bg="gray100"
  233. minW={70}
  234. px={12}
  235. ml={5}
  236. h={25}
  237. py={2}
  238. lineHeight={21}
  239. fontSize="md"
  240. keyboardType="numeric"
  241. onChangeText={setinventory}
  242. />
  243. </Div>
  244. <Div h={1} bg="gray100" my={20} />
  245. <Div>
  246. <Div alignSelf="flex-start" pb={10}>
  247. <Button
  248. appearance="outline"
  249. onPress={() => {
  250. navigation.navigate("GoodsSpecification", {
  251. goodsId: goodsId,
  252. });
  253. }}
  254. >
  255. 编辑规格
  256. </Button>
  257. </Div>
  258. <Div w={200}>
  259. {goodsSpecification.map((item, index) => {
  260. return (
  261. <Div key={index}>
  262. {item.parent ? (
  263. <Div row alignItems="center" mt={3} pl={20}>
  264. <Text fontSize="md" flex={1}>
  265. 添加 {item.name}
  266. </Text>
  267. <Text fontSize="sm" color="red500">
  268. ¥{item.amount || 0}
  269. </Text>
  270. </Div>
  271. ) : (
  272. <Div row mt={10}>
  273. <Text flex={1} fonySize="xl">
  274. 分类名: {item.name}
  275. </Text>
  276. <Text fontSize="sm">
  277. {item.multiple ? IQYCDU : GVDYKL}
  278. </Text>
  279. </Div>
  280. )}
  281. </Div>
  282. );
  283. })}
  284. </Div>
  285. </Div>
  286. <Div h={1} bg="gray100" my={20} />
  287. <Div>
  288. <Text fontSize="sm" minW={70} mb={10}>
  289. 商品简介
  290. </Text>
  291. <Input
  292. placeholder="添加商品简介(不超过50字)"
  293. value={introduction}
  294. bg="gray100"
  295. px={12}
  296. onChangeText={setintroduction}
  297. multiline
  298. numberOfLines={4}
  299. maxLength={50}
  300. textAlignVertical="top"
  301. />
  302. <Div position="absolute" right={12} bottom={12}>
  303. <Text fontSize="xs" color="gary500">
  304. {introduction.length}
  305. /50
  306. </Text>
  307. </Div>
  308. </Div>
  309. <Div h={1} bg="gray100" my={20} />
  310. <Div row alignItems="center">
  311. <Text fontSize="sm" minW={70}>
  312. 原价
  313. </Text>
  314. <Input
  315. value={amount}
  316. h={30}
  317. py={5}
  318. lineHeight={20}
  319. fontSize="xl"
  320. bg="gray100"
  321. minW={70}
  322. px={12}
  323. ml={5}
  324. keyboardType="numeric"
  325. onChangeText={setamount}
  326. />
  327. </Div>
  328. <Div row alignItems="center" my={10}>
  329. <Text fontSize="sm" minW={70}>
  330. 优惠价
  331. </Text>
  332. <Input
  333. value={discountAmount}
  334. h={30}
  335. py={5}
  336. lineHeight={20}
  337. fontSize="xl"
  338. bg="gray100"
  339. minW={70}
  340. px={12}
  341. ml={5}
  342. keyboardType="numeric"
  343. onChangeText={setdiscountAmount}
  344. />
  345. </Div>
  346. <Div row alignItems="center" my={10}>
  347. <Text fontSize="sm" minW={70}>
  348. 包装价格
  349. </Text>
  350. <Input
  351. value={packingPrice}
  352. h={30}
  353. py={5}
  354. lineHeight={20}
  355. fontSize="xl"
  356. bg="gray100"
  357. minW={70}
  358. px={12}
  359. ml={5}
  360. keyboardType="numeric"
  361. onChangeText={setpackingPrice}
  362. />
  363. </Div>
  364. <Div row alignItems="center" my={10}>
  365. <Text fontSize="sm" minW={70}>
  366. 供应时间
  367. </Text>
  368. <OpenTime
  369. submit={(_week, _startTime, _endTime) => {
  370. changeWeek(_week);
  371. changeStartTime(_startTime);
  372. changeEndTime(_endTime);
  373. }}
  374. week={week}
  375. startTime={startTime}
  376. endTime={endTime}
  377. />
  378. </Div>
  379. <Div my={20} minW={112} alignSelf="center">
  380. <Button
  381. status="primary"
  382. onPress={() => {
  383. loading();
  384. const info = { ...goodsInfo };
  385. delete info.merchant;
  386. delete info.specifications;
  387. delete info.isFullReduction;
  388. httpPost(
  389. "/goods/save",
  390. {
  391. id: goodsId,
  392. merchantId: info.merchantId,
  393. name,
  394. amount,
  395. discountAmount,
  396. inventory,
  397. week,
  398. startTime,
  399. endTime,
  400. introduction,
  401. img,
  402. packingPrice,
  403. },
  404. { body: "json" },
  405. true
  406. )
  407. .then(res => {
  408. return saveClassByList(postByList, res.id);
  409. })
  410. .then(() => {
  411. success("提交成功");
  412. navigation.goBack();
  413. })
  414. .finally(() => {
  415. clearLoading();
  416. });
  417. }}
  418. >
  419. 提交审核
  420. </Button>
  421. </Div>
  422. </Div>
  423. <Div bg="gray100">
  424. <Text lineHeight={45} px={15} fontSize="xl">
  425. 商品评价
  426. </Text>
  427. {comments.map(item => {
  428. return <CommentItem info={item} key={item.goodsAppraise} />;
  429. })}
  430. {comments.length === 0 && (
  431. <Div px={10} py={20}>
  432. <Text color="gray300" textAlign="center">
  433. 暂无数据
  434. </Text>
  435. </Div>
  436. )}
  437. </Div>
  438. </ScrollView>
  439. </>
  440. );
  441. }