filter-bar.uvue 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  1. <template>
  2. <cl-page>
  3. <view class="p-3">
  4. <demo-item :label="t('基础用法')">
  5. <cl-filter-bar>
  6. <!-- 下拉框 -->
  7. <cl-filter-item
  8. label="综合排序"
  9. type="select"
  10. :value="1"
  11. :options="coreOptions"
  12. :pt="{
  13. className: 'w-[220rpx] !flex-none'
  14. }"
  15. @change="onOptionsChange"
  16. ></cl-filter-item>
  17. <!-- 排序 -->
  18. <cl-filter-item
  19. label="销量"
  20. type="sort"
  21. value="desc"
  22. @change="onSortChange"
  23. ></cl-filter-item>
  24. <!-- 开关 -->
  25. <cl-filter-item
  26. label="国补"
  27. type="switch"
  28. :value="false"
  29. @change="onSwitchChange"
  30. ></cl-filter-item>
  31. <!-- 自定义 -->
  32. <view
  33. class="flex flex-row items-center justify-center flex-1"
  34. @tap="openFilter"
  35. >
  36. <cl-text>筛选</cl-text>
  37. <cl-icon name="filter-line"></cl-icon>
  38. </view>
  39. </cl-filter-bar>
  40. </demo-item>
  41. <demo-item>
  42. <cl-text pre-wrap :pt="{ className: '!text-sm p-2' }">{{
  43. JSON.stringify(filterForm, null, 4)
  44. }}</cl-text>
  45. </demo-item>
  46. <demo-item>
  47. <cl-text pre-wrap :pt="{ className: '!text-sm p-2' }">{{
  48. JSON.stringify(searchForm, null, 4)
  49. }}</cl-text>
  50. </demo-item>
  51. </view>
  52. <!-- 自定义筛选 -->
  53. <cl-popup
  54. v-model="filterVisible"
  55. :title="t('筛选')"
  56. direction="right"
  57. size="80%"
  58. :show-header="false"
  59. >
  60. <view class="flex flex-col h-full">
  61. <scroll-view class="flex-1">
  62. <cl-form :pt="{ className: 'p-3' }">
  63. <cl-form-item label="服务/折扣">
  64. <cl-row :gutter="20">
  65. <cl-col :span="8" v-for="(item, index) in disOptions" :key="index">
  66. <cl-checkbox
  67. v-model="searchForm.dis"
  68. :label="item.label"
  69. :value="item.value"
  70. :show-icon="false"
  71. :pt="{
  72. className: parseClass([
  73. 'mb-3 p-2 rounded-lg justify-center border border-solid border-transparent',
  74. [isDark, 'bg-surface-800', 'bg-surface-100'],
  75. [
  76. searchForm.dis.includes(item.value),
  77. `${isDark ? '!bg-surface-700' : '!bg-white'} !border-primary-500`
  78. ]
  79. ]),
  80. label: {
  81. className: '!text-sm'
  82. }
  83. }"
  84. ></cl-checkbox>
  85. </cl-col>
  86. </cl-row>
  87. </cl-form-item>
  88. <cl-form-item label="价格区间">
  89. <view class="flex flex-row items-center">
  90. <cl-input
  91. v-model="searchForm.minPrice"
  92. type="digit"
  93. placeholder="最低价"
  94. :pt="{
  95. className: 'flex-1',
  96. inner: {
  97. className: 'text-center'
  98. }
  99. }"
  100. ></cl-input>
  101. <cl-text
  102. :pt="{
  103. className: 'px-2'
  104. }"
  105. >~</cl-text
  106. >
  107. <cl-input
  108. v-model="searchForm.maxPrice"
  109. type="digit"
  110. placeholder="最高价"
  111. :pt="{
  112. className: 'flex-1',
  113. inner: {
  114. className: 'text-center'
  115. }
  116. }"
  117. ></cl-input>
  118. </view>
  119. </cl-form-item>
  120. <cl-form-item label="品牌">
  121. <cl-row :gutter="20">
  122. <cl-col
  123. :span="8"
  124. v-for="(item, index) in brandOptions"
  125. :key="index"
  126. >
  127. <cl-checkbox
  128. v-model="searchForm.brand"
  129. :label="item.label"
  130. :value="item.value"
  131. :show-icon="false"
  132. :pt="{
  133. className: parseClass([
  134. 'mb-3 p-2 rounded-lg justify-center border border-solid border-transparent',
  135. [isDark, 'bg-surface-800', 'bg-surface-100'],
  136. [
  137. searchForm.brand.includes(item.value),
  138. `${isDark ? '!bg-surface-700' : '!bg-white'} !border-primary-500`
  139. ]
  140. ]),
  141. label: {
  142. className: '!text-sm'
  143. }
  144. }"
  145. ></cl-checkbox>
  146. </cl-col>
  147. </cl-row>
  148. </cl-form-item>
  149. <cl-form-item label="内存">
  150. <cl-row :gutter="20">
  151. <cl-col
  152. :span="8"
  153. v-for="(item, index) in memoryOptions"
  154. :key="index"
  155. >
  156. <cl-radio
  157. v-model="searchForm.memory"
  158. :label="item.label"
  159. :value="item.value"
  160. :show-icon="false"
  161. :pt="{
  162. className: parseClass([
  163. 'mb-3 p-2 rounded-lg justify-center border border-solid border-transparent',
  164. [isDark, 'bg-surface-800', 'bg-surface-100'],
  165. [
  166. searchForm.memory == item.value,
  167. `${isDark ? '!bg-surface-700' : '!bg-white'} !border-primary-500`
  168. ]
  169. ]),
  170. label: {
  171. className: '!text-sm'
  172. }
  173. }"
  174. ></cl-radio>
  175. </cl-col>
  176. </cl-row>
  177. </cl-form-item>
  178. <cl-form-item label="颜色">
  179. <cl-row :gutter="20">
  180. <cl-col
  181. :span="8"
  182. v-for="(item, index) in colorOptions"
  183. :key="index"
  184. >
  185. <cl-radio
  186. v-model="searchForm.color"
  187. :label="item.label"
  188. :value="item.value"
  189. :show-icon="false"
  190. :pt="{
  191. className: parseClass([
  192. 'mb-3 p-2 rounded-lg justify-center border border-solid border-transparent',
  193. [isDark, 'bg-surface-800', 'bg-surface-100'],
  194. [
  195. searchForm.color == item.value,
  196. `${isDark ? '!bg-surface-700' : '!bg-white'} !border-primary-500`
  197. ]
  198. ]),
  199. label: {
  200. className: '!text-sm'
  201. }
  202. }"
  203. ></cl-radio>
  204. </cl-col>
  205. </cl-row>
  206. </cl-form-item>
  207. </cl-form>
  208. </scroll-view>
  209. <view class="flex flex-row p-3">
  210. <cl-button
  211. type="info"
  212. text
  213. border
  214. :pt="{
  215. className: 'flex-1'
  216. }"
  217. @tap="closeFilter"
  218. >{{ t("取消") }}</cl-button
  219. >
  220. <cl-button
  221. :pt="{
  222. className: 'flex-1'
  223. }"
  224. @tap="submit"
  225. >{{ t("确定") }}</cl-button
  226. >
  227. </view>
  228. <cl-safe-area type="bottom"></cl-safe-area>
  229. </view>
  230. </cl-popup>
  231. </cl-page>
  232. </template>
  233. <script lang="ts" setup>
  234. import { t } from "@/locale";
  235. import DemoItem from "../components/item.uvue";
  236. import { reactive, ref } from "vue";
  237. import { useUi, type ClSelectOption } from "@/uni_modules/cool-ui";
  238. import { isDark, parseClass } from "@/cool";
  239. const ui = useUi();
  240. const filterVisible = ref(false);
  241. function openFilter() {
  242. filterVisible.value = true;
  243. }
  244. function closeFilter() {
  245. filterVisible.value = false;
  246. }
  247. function submit() {
  248. closeFilter();
  249. ui.showLoading();
  250. setTimeout(() => {
  251. ui.hideLoading();
  252. }, 1000);
  253. }
  254. const coreOptions = ref<ClSelectOption[]>([
  255. {
  256. label: "综合排序",
  257. value: 1
  258. },
  259. {
  260. label: "价格从高到底",
  261. value: 2
  262. },
  263. {
  264. label: "价格从低到高",
  265. value: 3
  266. }
  267. ]);
  268. type Option = {
  269. label: string;
  270. value: string;
  271. };
  272. const disOptions = ref<Option[]>([
  273. {
  274. label: "百亿补贴",
  275. value: "billion_subsidy"
  276. },
  277. {
  278. label: "以旧换新",
  279. value: "trade_in"
  280. },
  281. {
  282. label: "分期免息",
  283. value: "installment"
  284. },
  285. {
  286. label: "包邮",
  287. value: "free_shipping"
  288. },
  289. {
  290. label: "促销",
  291. value: "promotion"
  292. },
  293. {
  294. label: "价保",
  295. value: "price_protection"
  296. },
  297. {
  298. label: "仅看有货",
  299. value: "in_stock"
  300. },
  301. {
  302. label: "货到付款",
  303. value: "cod"
  304. }
  305. ]);
  306. const brandOptions = ref<Option[]>([
  307. {
  308. label: "华为",
  309. value: "huawei"
  310. },
  311. {
  312. label: "苹果",
  313. value: "apple"
  314. },
  315. {
  316. label: "小米",
  317. value: "xiaomi"
  318. },
  319. {
  320. label: "三星",
  321. value: "samsung"
  322. },
  323. {
  324. label: "OPPO",
  325. value: "oppo"
  326. },
  327. {
  328. label: "vivo",
  329. value: "vivo"
  330. },
  331. {
  332. label: "荣耀",
  333. value: "honor"
  334. }
  335. ]);
  336. const colorOptions = ref<Option[]>([
  337. {
  338. label: "红色",
  339. value: "red"
  340. },
  341. {
  342. label: "蓝色",
  343. value: "blue"
  344. },
  345. {
  346. label: "黑色",
  347. value: "black"
  348. },
  349. {
  350. label: "白色",
  351. value: "white"
  352. },
  353. {
  354. label: "金色",
  355. value: "gold"
  356. },
  357. {
  358. label: "银色",
  359. value: "silver"
  360. },
  361. {
  362. label: "绿色",
  363. value: "green"
  364. },
  365. {
  366. label: "紫色",
  367. value: "purple"
  368. },
  369. {
  370. label: "灰色",
  371. value: "gray"
  372. },
  373. {
  374. label: "粉色",
  375. value: "pink"
  376. }
  377. ]);
  378. const memoryOptions = ref<Option[]>([
  379. {
  380. label: "128GB",
  381. value: "128"
  382. },
  383. {
  384. label: "256GB",
  385. value: "256"
  386. },
  387. {
  388. label: "512GB",
  389. value: "512"
  390. },
  391. {
  392. label: "1TB",
  393. value: "1024"
  394. }
  395. ]);
  396. type SearchForm = {
  397. dis: string[];
  398. minPrice: string;
  399. maxPrice: string;
  400. brand: string[];
  401. memory: string;
  402. color: string;
  403. };
  404. const searchForm = ref<SearchForm>({
  405. dis: [],
  406. minPrice: "50",
  407. maxPrice: "300",
  408. brand: [],
  409. memory: "",
  410. color: ""
  411. });
  412. type FilterForm = {
  413. core: number;
  414. sort: string;
  415. switch: boolean;
  416. };
  417. const filterForm = reactive<FilterForm>({
  418. core: 0,
  419. sort: "none",
  420. switch: false
  421. });
  422. function onOptionsChange(val: number) {
  423. console.log(val);
  424. filterForm.core = val;
  425. }
  426. function onSortChange(val: string) {
  427. console.log(val);
  428. filterForm.sort = val;
  429. }
  430. function onSwitchChange(val: boolean) {
  431. console.log(val);
  432. filterForm.switch = val;
  433. }
  434. </script>