filter-bar.uvue 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  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. </view>
  229. </cl-popup>
  230. </cl-page>
  231. </template>
  232. <script lang="ts" setup>
  233. import { t } from "@/locale";
  234. import DemoItem from "../components/item.uvue";
  235. import { reactive, ref } from "vue";
  236. import { useUi, type ClSelectOption } from "@/uni_modules/cool-ui";
  237. import { isDark, parseClass } from "@/cool";
  238. const ui = useUi();
  239. const filterVisible = ref(false);
  240. function openFilter() {
  241. filterVisible.value = true;
  242. }
  243. function closeFilter() {
  244. filterVisible.value = false;
  245. }
  246. function submit() {
  247. closeFilter();
  248. ui.showLoading();
  249. setTimeout(() => {
  250. ui.hideLoading();
  251. }, 1000);
  252. }
  253. const coreOptions = ref<ClSelectOption[]>([
  254. {
  255. label: "综合排序",
  256. value: 1
  257. },
  258. {
  259. label: "价格从高到底",
  260. value: 2
  261. },
  262. {
  263. label: "价格从低到高",
  264. value: 3
  265. }
  266. ]);
  267. type Option = {
  268. label: string;
  269. value: string;
  270. };
  271. const disOptions = ref<Option[]>([
  272. {
  273. label: "百亿补贴",
  274. value: "billion_subsidy"
  275. },
  276. {
  277. label: "以旧换新",
  278. value: "trade_in"
  279. },
  280. {
  281. label: "分期免息",
  282. value: "installment"
  283. },
  284. {
  285. label: "包邮",
  286. value: "free_shipping"
  287. },
  288. {
  289. label: "促销",
  290. value: "promotion"
  291. },
  292. {
  293. label: "价保",
  294. value: "price_protection"
  295. },
  296. {
  297. label: "仅看有货",
  298. value: "in_stock"
  299. },
  300. {
  301. label: "货到付款",
  302. value: "cod"
  303. }
  304. ]);
  305. const brandOptions = ref<Option[]>([
  306. {
  307. label: "华为",
  308. value: "huawei"
  309. },
  310. {
  311. label: "苹果",
  312. value: "apple"
  313. },
  314. {
  315. label: "小米",
  316. value: "xiaomi"
  317. },
  318. {
  319. label: "三星",
  320. value: "samsung"
  321. },
  322. {
  323. label: "OPPO",
  324. value: "oppo"
  325. },
  326. {
  327. label: "vivo",
  328. value: "vivo"
  329. },
  330. {
  331. label: "荣耀",
  332. value: "honor"
  333. }
  334. ]);
  335. const colorOptions = ref<Option[]>([
  336. {
  337. label: "红色",
  338. value: "red"
  339. },
  340. {
  341. label: "蓝色",
  342. value: "blue"
  343. },
  344. {
  345. label: "黑色",
  346. value: "black"
  347. },
  348. {
  349. label: "白色",
  350. value: "white"
  351. },
  352. {
  353. label: "金色",
  354. value: "gold"
  355. },
  356. {
  357. label: "银色",
  358. value: "silver"
  359. },
  360. {
  361. label: "绿色",
  362. value: "green"
  363. },
  364. {
  365. label: "紫色",
  366. value: "purple"
  367. },
  368. {
  369. label: "灰色",
  370. value: "gray"
  371. },
  372. {
  373. label: "粉色",
  374. value: "pink"
  375. }
  376. ]);
  377. const memoryOptions = ref<Option[]>([
  378. {
  379. label: "128GB",
  380. value: "128"
  381. },
  382. {
  383. label: "256GB",
  384. value: "256"
  385. },
  386. {
  387. label: "512GB",
  388. value: "512"
  389. },
  390. {
  391. label: "1TB",
  392. value: "1024"
  393. }
  394. ]);
  395. type SearchForm = {
  396. dis: string[];
  397. minPrice: string;
  398. maxPrice: string;
  399. brand: string[];
  400. memory: string;
  401. color: string;
  402. };
  403. const searchForm = ref<SearchForm>({
  404. dis: [],
  405. minPrice: "50",
  406. maxPrice: "300",
  407. brand: [],
  408. memory: "",
  409. color: ""
  410. });
  411. type FilterForm = {
  412. core: number;
  413. sort: string;
  414. switch: boolean;
  415. };
  416. const filterForm = reactive<FilterForm>({
  417. core: 0,
  418. sort: "none",
  419. switch: false
  420. });
  421. function onOptionsChange(val: number) {
  422. console.log(val);
  423. filterForm.core = val;
  424. }
  425. function onSortChange(val: string) {
  426. console.log(val);
  427. filterForm.sort = val;
  428. }
  429. function onSwitchChange(val: boolean) {
  430. console.log(val);
  431. filterForm.switch = val;
  432. }
  433. </script>