diff --git a/web-admin/src/components/business/column-header-filter/index.vue b/web-admin/src/components/business/column-header-filter/index.vue
index d5ef7a641..2a73a6070 100644
--- a/web-admin/src/components/business/column-header-filter/index.vue
+++ b/web-admin/src/components/business/column-header-filter/index.vue
@@ -569,4 +569,33 @@
.col-header-with-filter__label.is-right {
text-align: right;
}
+
+ .col-header-sort-pair {
+ display: inline-flex;
+ flex-direction: column;
+ flex-shrink: 0;
+ gap: 0;
+ line-height: 1;
+ }
+
+ .col-header-sort-btn {
+ display: block;
+ width: 14px;
+ height: 10px;
+ padding: 0;
+ border: none;
+ background: transparent;
+ color: #cbd5e1;
+ font-size: 9px;
+ line-height: 1;
+ cursor: pointer;
+ }
+
+ .col-header-sort-btn:hover {
+ color: #64748b;
+ }
+
+ .col-header-sort-btn.on {
+ color: #059669;
+ }
diff --git a/web-admin/src/components/business/crm-col-filter-header/index.vue b/web-admin/src/components/business/crm-col-filter-header/index.vue
index 28abe3ffd..79228d5c1 100644
--- a/web-admin/src/components/business/crm-col-filter-header/index.vue
+++ b/web-admin/src/components/business/crm-col-filter-header/index.vue
@@ -5,6 +5,28 @@
class="col-header-with-filter__label"
:class="{ 'is-left': align === 'left', 'is-right': align === 'right' }"
>{{ label }}
+
(props.injectKey, null)
+ const sortApi = inject<{
+ setSort: (prop: string, order: 'asc' | 'desc') => void
+ isSortActive: (prop: string, order?: 'asc' | 'desc') => boolean
+ } | null>('crmColumnSort', null)
+
const def = computed(() => api?.defMap.get(props.prop))
const label = computed(() => def.value?.label || props.prop)
const options = computed(() =>
def.value?.type === 'enum' ? api?.enumOptionsFor(props.prop) : undefined
)
+ const showSort = computed(
+ () => Boolean(sortApi && def.value?.type === 'datetime')
+ )