jianghu-ui 1.0.4 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jianghu-ui",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "JianghuJS UI Component Library with Storybook, Vue 2, and Vuetify 2",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
@@ -123,8 +123,8 @@
123
123
  </v-list>
124
124
  </div>
125
125
 
126
- <div v-if="level >= 2" class="jh-cascader-column">
127
- <v-list dense class="pa-0" v-if="cities.length">
126
+ <div v-if="level >= 2 && internalValue.province && cities.length" class="jh-cascader-column">
127
+ <v-list dense class="pa-0">
128
128
  <v-list-item v-for="item in cities" :key="item.code" @click="onCityClick(item)" :class="{'v-item--active v-list-item--active primary--text': internalValue.city === item.code}">
129
129
  <v-list-item-content><v-list-item-title :title="item.name">{{ item.name }}</v-list-item-title></v-list-item-content>
130
130
  <v-list-item-action v-if="level > 2"><v-icon small>mdi-chevron-right</v-icon></v-list-item-action>
@@ -132,8 +132,8 @@
132
132
  </v-list>
133
133
  </div>
134
134
 
135
- <div v-if="level >= 3" class="jh-cascader-column">
136
- <v-list dense class="pa-0" v-if="districts.length">
135
+ <div v-if="level >= 3 && internalValue.city && districts.length" class="jh-cascader-column">
136
+ <v-list dense class="pa-0">
137
137
  <v-list-item v-for="item in districts" :key="item.code" @click="onDistrictClick(item)" :class="{'v-item--active v-list-item--active primary--text': internalValue.district === item.code}">
138
138
  <v-list-item-content><v-list-item-title :title="item.name">{{ item.name }}</v-list-item-title></v-list-item-content>
139
139
  <v-list-item-action v-if="level > 3"><v-icon small>mdi-chevron-right</v-icon></v-list-item-action>
@@ -141,8 +141,8 @@
141
141
  </v-list>
142
142
  </div>
143
143
 
144
- <div v-if="level >= 4" class="jh-cascader-column">
145
- <v-list dense class="pa-0" v-if="towns.length">
144
+ <div v-if="level >= 4 && internalValue.district && towns.length" class="jh-cascader-column">
145
+ <v-list dense class="pa-0">
146
146
  <v-list-item v-for="item in towns" :key="item.code" @click="onTownClick(item)" :class="{'v-item--active v-list-item--active primary--text': internalValue.town === item.code}">
147
147
  <v-list-item-content><v-list-item-title :title="item.name">{{ item.name }}</v-list-item-title></v-list-item-content>
148
148
  </v-list-item>
@@ -1442,3 +1442,74 @@ export const SelectionAlertRender = {
1442
1442
  `
1443
1443
  })
1444
1444
  };
1445
+
1446
+ // 受控服务端分页 (完全由父组件控制)
1447
+ export const 受控服务端分页 = {
1448
+ render: () => ({
1449
+ components: { JhTable },
1450
+ data() {
1451
+ return {
1452
+ headers: sampleHeaders,
1453
+ items: [],
1454
+ loading: false,
1455
+ page: 1,
1456
+ itemsPerPage: 10,
1457
+ serverItemsLength: 0,
1458
+ };
1459
+ },
1460
+ mounted() {
1461
+ this.loadData();
1462
+ },
1463
+ watch: {
1464
+ page() {
1465
+ console.log('Page changed to:', this.page);
1466
+ this.loadData();
1467
+ },
1468
+ itemsPerPage() {
1469
+ console.log('Items per page changed to:', this.itemsPerPage);
1470
+ // 通常改变每页大小时建议重置到第一页,但这里取决于业务逻辑
1471
+ // 注意:v-data-table 可能会自动触发 update:page 为 1
1472
+ this.loadData();
1473
+ },
1474
+ },
1475
+ methods: {
1476
+ async loadData() {
1477
+ this.loading = true;
1478
+ console.log(`Loading data: page=${this.page}, size=${this.itemsPerPage}`);
1479
+
1480
+ // 模拟 API 延迟
1481
+ await new Promise(resolve => setTimeout(resolve, 300));
1482
+
1483
+ const total = allMockData.length;
1484
+ const start = (this.page - 1) * this.itemsPerPage;
1485
+ const end = start + this.itemsPerPage;
1486
+
1487
+ this.items = allMockData.slice(start, end);
1488
+ this.serverItemsLength = total;
1489
+ this.loading = false;
1490
+ },
1491
+ },
1492
+ template: `
1493
+ <div>
1494
+ <div class="mb-4 pa-4 orange lighten-5 rounded">
1495
+ <strong>受控服务端分页示例 (无 request 函数)</strong>
1496
+ <p class="mb-0 mt-2">完全由父组件控制 page 和 itemsPerPage,模拟传统的 v-data-table 服务端分页用法。</p>
1497
+ <div class="mt-2">
1498
+ Page: {{ page }} | ItemsPerPage: {{ itemsPerPage }} | Total: {{ serverItemsLength }}
1499
+ </div>
1500
+ </div>
1501
+ <jh-table
1502
+ :headers="headers"
1503
+ :items="items"
1504
+ :loading="loading"
1505
+ :page.sync="page"
1506
+ :items-per-page.sync="itemsPerPage"
1507
+ :server-items-length="serverItemsLength"
1508
+ :footer-props="{
1509
+ 'items-per-page-options': [5, 10, 20]
1510
+ }"
1511
+ />
1512
+ </div>
1513
+ `,
1514
+ }),
1515
+ };
@@ -844,6 +844,23 @@ export default {
844
844
  dense: {
845
845
  type: Boolean,
846
846
  default: false
847
+ },
848
+ // ========== v-data-table 透传 Props (补充) ==========
849
+ page: {
850
+ type: Number,
851
+ default: undefined
852
+ },
853
+ serverItemsLength: {
854
+ type: Number,
855
+ default: undefined
856
+ },
857
+ value: {
858
+ type: Array,
859
+ default: undefined
860
+ },
861
+ context: {
862
+ type: Object,
863
+ default: null
847
864
  }
848
865
  },
849
866
  data() {
@@ -852,13 +869,13 @@ export default {
852
869
  searchInputInternal: this.searchInput,
853
870
  currentLoading: this.loading,
854
871
  currentItems: this.items || [],
855
- currentPage: this.pagination ? this.pagination.current || 1 : 1,
872
+ currentPage: this.page !== undefined ? this.page : (this.pagination ? this.pagination.current || 1 : 1),
856
873
  currentItemsPerPage: this.itemsPerPage,
857
- serverItemsLength: -1,
874
+ serverItemsLength: this.serverItemsLength !== undefined ? this.serverItemsLength : -1,
858
875
  internalColumns: [],
859
876
  currentDensity: this.size,
860
877
  isFullscreen: false,
861
- selectedItems: [],
878
+ selectedItems: this.value || [],
862
879
  filterValues: {},
863
880
  pollingTimer: null,
864
881
  searchDebounceTimer: null,
@@ -1130,6 +1147,26 @@ export default {
1130
1147
  }
1131
1148
  },
1132
1149
  watch: {
1150
+ page(val) {
1151
+ if (val !== undefined && val !== this.currentPage) {
1152
+ this.currentPage = val;
1153
+ }
1154
+ },
1155
+ serverItemsLength(val) {
1156
+ if (val !== undefined) {
1157
+ this.serverItemsLength = val;
1158
+ }
1159
+ },
1160
+ value(val) {
1161
+ if (val !== undefined) {
1162
+ this.selectedItems = val;
1163
+ }
1164
+ },
1165
+ itemsPerPage(val) {
1166
+ if (val !== undefined && val !== this.currentItemsPerPage) {
1167
+ this.currentItemsPerPage = val;
1168
+ }
1169
+ },
1133
1170
  headers: {
1134
1171
  immediate: true,
1135
1172
  handler(val) {
@@ -1267,7 +1304,7 @@ export default {
1267
1304
  },
1268
1305
  getColumnRawValue(header, item, value) {
1269
1306
  if (header && typeof header.valueGetter === 'function') {
1270
- return header.valueGetter(item, header);
1307
+ return header.valueGetter.call(this.context, item, header);
1271
1308
  }
1272
1309
  if (value !== undefined) return value;
1273
1310
  const key = header?.value;
@@ -1276,7 +1313,7 @@ export default {
1276
1313
  },
1277
1314
  applyValueFormatter(header, rawValue, item, index = 0) {
1278
1315
  if (header && typeof header.valueFormatter === 'function') {
1279
- const formatted = header.valueFormatter(rawValue, item, header, index);
1316
+ const formatted = header.valueFormatter.call(this.context, rawValue, item, header, index);
1280
1317
  if (formatted !== undefined && formatted !== null) {
1281
1318
  return formatted;
1282
1319
  }
@@ -1537,7 +1574,7 @@ export default {
1537
1574
  if (!this.actionColumn || !this.actionColumn.buttons) return [];
1538
1575
  return this.actionColumn.buttons.filter(btn => {
1539
1576
  if (typeof btn.visible === 'function') {
1540
- return btn.visible(row);
1577
+ return btn.visible.call(this.context, row);
1541
1578
  }
1542
1579
  return btn.visible !== false;
1543
1580
  });
@@ -1549,7 +1586,7 @@ export default {
1549
1586
  if (!confirmed) return;
1550
1587
  }
1551
1588
  if (btn.onClick) {
1552
- await btn.onClick(row);
1589
+ await btn.onClick.call(this.context, row);
1553
1590
  }
1554
1591
  },
1555
1592
  // 复制到剪贴板
@@ -1587,7 +1624,7 @@ export default {
1587
1624
  this.$emit('selection-change', payload);
1588
1625
  this.$emit('input', selectedItems);
1589
1626
  if (this.rowSelection && typeof this.rowSelection.onChange === 'function') {
1590
- this.rowSelection.onChange(payload.selectedRowKeys, selectedItems);
1627
+ this.rowSelection.onChange.call(this.context, payload.selectedRowKeys, selectedItems);
1591
1628
  }
1592
1629
  },
1593
1630
  // 页码改变
@@ -1630,6 +1667,7 @@ export default {
1630
1667
  const filters = this.transformFilterValues(queryData);
1631
1668
  this.filterValues = filters;
1632
1669
  this.currentPage = 1; // 重置到第一页
1670
+ this.$emit('update:page', 1);
1633
1671
  this.$emit('filter-search', filters);
1634
1672
  if (this.request) {
1635
1673
  this.reload();
@@ -1639,6 +1677,7 @@ export default {
1639
1677
  handleFilterReset() {
1640
1678
  this.filterValues = {};
1641
1679
  this.currentPage = 1; // 重置到第一页
1680
+ this.$emit('update:page', 1);
1642
1681
  this.$emit('filter-reset');
1643
1682
  if (this.request) {
1644
1683
  this.reload();
@@ -1650,7 +1689,7 @@ export default {
1650
1689
  const value = queryData[key];
1651
1690
  const meta = this.filterFieldMetaMap[key];
1652
1691
  if (meta && typeof meta.transform === 'function') {
1653
- const result = meta.transform(value, queryData);
1692
+ const result = meta.transform.call(this.context, value, queryData);
1654
1693
  if (result && typeof result === 'object' && !Array.isArray(result)) {
1655
1694
  Object.assign(filters, result);
1656
1695
  return;
@@ -1816,6 +1855,7 @@ export default {
1816
1855
  // 重置到第一页
1817
1856
  reset() {
1818
1857
  this.currentPage = 1;
1858
+ this.$emit('update:page', 1);
1819
1859
  this.reload();
1820
1860
  },
1821
1861
  // 清空选择
@@ -1874,7 +1914,7 @@ export default {
1874
1914
  const snapshot = this.getColumnStateSnapshot();
1875
1915
  this.$emit('columns-state-change', snapshot);
1876
1916
  if (this.columnsState && typeof this.columnsState.onChange === 'function') {
1877
- this.columnsState.onChange(snapshot);
1917
+ this.columnsState.onChange.call(this.context, snapshot);
1878
1918
  }
1879
1919
  this.persistColumnState(snapshot);
1880
1920
  },