Slider.tsx 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. import { View, Text, Image } from '@tarojs/components'
  2. import './Slider.scss'
  3. import { ColorType } from '@/context/themes/color'
  4. import { useEffect, useRef, useState } from 'react';
  5. import { rpxToPx } from '@/utils/tools';
  6. import Taro from '@tarojs/taro';
  7. import { useSelector } from 'react-redux';
  8. import { useTranslation } from 'react-i18next';
  9. import { jumpPage } from '@/features/trackTimeDuration/hooks/Common';
  10. var currentValue = 0;
  11. var lastValue = 0;
  12. export default function (props: { onChanged?: Function, value?: number, edit?: boolean, isPreMeal?: boolean, isPostMeal?: boolean, id?: string }) {
  13. const sliderWidth = 578;
  14. const [brightness, setBrightness] = useState(props.value ? props.value * 10 : 0);
  15. const [isSliding, setIsSliding] = useState(false);
  16. const [value, setValue] = useState(props.value ? props.value : 0)
  17. const [startX, setStartX] = useState(0);
  18. const common = useSelector((state: any) => state.common);
  19. const user = useSelector((state: any) => state.user);
  20. const [showArrow, setShowArrow] = useState(true)
  21. const { t } = useTranslation()
  22. useEffect(() => {
  23. // if (props.value) {
  24. // setBrightness(props.value * 10)
  25. // }
  26. }, [props.value])
  27. const handleTouchStart = (event) => {
  28. if (!user.isLogin) {
  29. jumpPage('/pages/account/ChooseAuth', 'ChooseAuth')
  30. return
  31. }
  32. setIsSliding(true);
  33. setShowArrow(false);
  34. setStartX(event.touches[0].clientX);
  35. };
  36. const handleTouchMove = (event) => {
  37. if (!user.isLogin) {
  38. return
  39. }
  40. if (isSliding) {
  41. const { touches } = event;
  42. const touchX = touches[0].clientX;
  43. const deltaX = touchX - startX;
  44. // console.log(deltaY,startY,touchY)
  45. // const containerHeight = rpxToPx(182); // 容器高度,根据实际情况调整
  46. let brightnessValue = brightness + deltaX / rpxToPx(sliderWidth - 120) * 100;// / containerHeight * 100;
  47. // 边界限制
  48. brightnessValue = Math.max(0, Math.min(brightnessValue, 100));
  49. brightnessValue = Math.round(brightnessValue)
  50. setStartX(touchX)
  51. setBrightness(brightnessValue);
  52. currentValue = brightnessValue;
  53. var data = calculateNumber(brightnessValue)
  54. if (lastValue != data && data == 5) {
  55. Taro.vibrateShort({
  56. type: 'light'
  57. })
  58. }
  59. lastValue = data
  60. setValue(data)
  61. }
  62. };
  63. const handleTouchEnd = () => {
  64. if (!user.isLogin) {
  65. return
  66. }
  67. setIsSliding(false);
  68. Taro.vibrateShort({
  69. type: 'light'
  70. })
  71. if (props.onChanged) {
  72. var obj = common.food_scales.filter((item: any) => {
  73. return item.point == value
  74. })
  75. Taro.showModal({
  76. title: props.isPreMeal ? t('feature.food.pre_meal_confirm_title', { score: value, desc: value < 5 ? '饿' : '饱' }) : t('feature.food.post_meal_confirm_title', { score: value, desc: value < 5 ? '饿' : '饱' }),
  77. content: obj[0].description ? obj[0].description : '暂无描述',
  78. success: function (res) {
  79. if (res.confirm) {
  80. props.onChanged && props.onChanged(value);
  81. }
  82. else {
  83. setShowArrow(true)
  84. if (props.isPreMeal) {
  85. setStartX(0);
  86. setBrightness(0)
  87. setValue(0)
  88. }
  89. else {
  90. setBrightness(props.value! * 10)
  91. setValue(props.value!)
  92. }
  93. }
  94. }
  95. })
  96. }
  97. if (props.edit) {
  98. // 松手后,滑块动画移动到最左边
  99. // Taro.showToast({
  100. // icon: 'none',
  101. // title: '请先上传!'
  102. // })
  103. Taro.showModal({
  104. title: t('feature.common.prompt'),
  105. content: t('feature.food.pre_meal_enforce_order_alert'),
  106. showCancel: false,
  107. confirmText: '好的',
  108. success: function (res) {
  109. if (res.confirm) {
  110. setShowArrow(true)
  111. setStartX(0);
  112. setBrightness(0)
  113. setValue(0)
  114. }
  115. }
  116. })
  117. // const animationId = requestAnimationFrame(moveToStart);
  118. // return () => cancelAnimationFrame(animationId);
  119. }
  120. };
  121. const moveToStart = () => {
  122. const newPosition = Math.max(currentValue - 8, 0);
  123. currentValue = newPosition
  124. setBrightness(newPosition)
  125. setValue(calculateNumber(newPosition))
  126. if (newPosition > 0) {
  127. requestAnimationFrame(moveToStart);
  128. } else {
  129. setStartX(0);
  130. setBrightness(0)
  131. }
  132. };
  133. function calculateOpacity(number) {
  134. if (number === 0 || number === 100) {
  135. return 1;
  136. } else if (number === 50) {
  137. return 0;
  138. } else if (number < 50) {
  139. return 1 - (number / 50);
  140. } else {
  141. return (number - 50) / 50;
  142. }
  143. }
  144. function calculateNumber(number) {
  145. if (number <= 2) {
  146. return 0;
  147. } else if (number <= 7) {
  148. return 0.5;
  149. } else {
  150. var result = Math.floor(number / 10);
  151. var decimal = number % 10;
  152. if (decimal >= 3 && decimal <= 7) {
  153. return result + 0.5;
  154. } else if (decimal >= 8 && decimal <= 9) {
  155. if (result == 9) {
  156. return 9.5
  157. }
  158. return result + 1;
  159. } else {
  160. return result;
  161. }
  162. }
  163. }
  164. function getTitle() {
  165. var obj = common.food_scales.filter((item: any) => {
  166. return item.point == value
  167. })
  168. return obj[0].name
  169. }
  170. function getDesc() {
  171. var obj = common.food_scales.filter((item: any) => {
  172. return item.point == value
  173. })
  174. return obj[0].description ?? '暂无描述'
  175. }
  176. function getSliderTitleClass() {
  177. if (props.isPostMeal) {
  178. if (showArrow) {
  179. return 'slider-tip-title-post'
  180. }
  181. }
  182. return value < 5 ? 'slider-tip-title' : 'slider-tip-title-post'
  183. }
  184. function getSliderDescClass() {
  185. if (props.isPostMeal) {
  186. if (showArrow) {
  187. return 'slider-tip-desc-post'
  188. }
  189. }
  190. return value < 5 ? 'slider-tip-desc' : 'slider-tip-desc-post'
  191. }
  192. function getSliderTitle() {
  193. if (props.isPostMeal) {
  194. if (showArrow) {
  195. return t('feature.food.slider_tip_post_meal_title')
  196. }
  197. }
  198. return value < 5 ?
  199. t('feature.food.slider_tip_pre_meal_title') :
  200. t('feature.food.slider_tip_post_meal_title')
  201. }
  202. function getSliderDesc() {
  203. if (props.isPostMeal) {
  204. if (showArrow) {
  205. return t('feature.food.slider_tip_post_meal_desc')
  206. }
  207. }
  208. return value < 5 ?
  209. t('feature.food.slider_tip_pre_meal_desc') :
  210. t('feature.food.slider_tip_post_meal_desc')
  211. }
  212. function getSliderBgColor() {
  213. if (props.isPostMeal) {
  214. if (showArrow) {
  215. return ColorType.food
  216. }
  217. }
  218. return value == 5 ? '#fff' : value < 5 ? ColorType.fast : ColorType.food
  219. }
  220. return <View style={{ display: 'flex', flexDirection: 'column', position: 'relative', width: rpxToPx(578) }}>
  221. <View className='slider-container'
  222. catchMove
  223. onTouchStart={handleTouchStart}
  224. onTouchMove={handleTouchMove}
  225. onTouchEnd={handleTouchEnd}>
  226. <View className='slider-tip-bg' style={{ width: (100 - brightness) * 0.01 * rpxToPx(sliderWidth) - brightness * 0.01 * rpxToPx(120) + brightness * 0.01 * rpxToPx(28) }}>
  227. <Text className={getSliderTitleClass()}>{getSliderTitle()}</Text>
  228. <Text className={getSliderDescClass()}>{getSliderDesc()}</Text>
  229. </View>
  230. <View className='slider-item-content'>
  231. <View className='slider-item-bg' style={{
  232. width: brightness * 0.01 * rpxToPx(sliderWidth - 126) + rpxToPx(112 + 2),
  233. backgroundColor: getSliderBgColor()//value == 5 ? '#fff' : value < 5 ? ColorType.fast : ColorType.food
  234. }}>
  235. {/* <View className='slider-item' style={{
  236. width: brightness * 0.01 * rpxToPx(sliderWidth - 126) + rpxToPx(112) + 1,
  237. backgroundColor: brightness <= 50 ? ColorType.fast : ColorType.food,
  238. opacity: calculateOpacity(brightness),
  239. }}>
  240. </View> */}
  241. </View>
  242. </View>
  243. {
  244. !showArrow ? <View className='slider-text-bg'>
  245. <Text className='slider-text'>{value}</Text>
  246. </View> :
  247. <View className='slider-arrow-bg' style={{ left: props.isPostMeal ? brightness * 0.01 * rpxToPx(sliderWidth - 120) : 0 }}>
  248. <Image src={require('@assets/images/arrow4.png')} className='slider-arrow' />
  249. </View>
  250. }
  251. </View>
  252. {
  253. isSliding && <View className='tooltip_bg'>
  254. <View style={{ flex: 1 }} />
  255. <View className='tooltip_content'>
  256. <Text className='tooltip_title' style={{ color: value == 5 ? '#fff' : value < 5 ? ColorType.fast : ColorType.food }}>{props.isPostMeal ? '餐后' : '餐前'}{getTitle()}</Text>
  257. <Text className='tooltip_desc'>{getDesc()}</Text>
  258. </View>
  259. <View className='tooltip_arrow' style={{ marginLeft: brightness * 0.01 * rpxToPx(sliderWidth - 120) + rpxToPx((120 - 50) / 2) }} />
  260. </View>
  261. }
  262. </View>
  263. }