|
|
@@ -28,6 +28,16 @@
|
|
|
<el-option label="全部分类" value="" />
|
|
|
<el-option v-for="opt in categoryOptions" :key="opt" :label="opt" :value="opt" />
|
|
|
</el-select>
|
|
|
+ <el-tag
|
|
|
+ v-if="sortState.length > 0"
|
|
|
+ closable
|
|
|
+ size="mini"
|
|
|
+ class="sort-tag"
|
|
|
+ @close="clearSort"
|
|
|
+ @click="clearSort"
|
|
|
+ >
|
|
|
+ {{ sortLabel }}
|
|
|
+ </el-tag>
|
|
|
<el-button type="primary" size="mini" icon="el-icon-plus" @click="openCreate">新建食材</el-button>
|
|
|
</div>
|
|
|
</div>
|
|
|
@@ -42,65 +52,95 @@
|
|
|
:max-height="tableHeight"
|
|
|
>
|
|
|
<el-table-column type="index" label="#" width="50" align="center" />
|
|
|
- <el-table-column prop="name" label="名称" min-width="120" fixed>
|
|
|
+ <el-table-column prop="name" label="名称" min-width="120" fixed :class-name="sortClass('name')">
|
|
|
<template slot-scope="{ row }">
|
|
|
<span style="font-weight: 500;">{{ row.name }}</span>
|
|
|
</template>
|
|
|
+ <template slot="header">
|
|
|
+ <span class="sort-header" @click.stop="onSortClick('name',$event)" @dblclick.stop="onSortToggle('name')">名称{{ sortIcon('name') }}</span>
|
|
|
+ </template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column prop="category" label="分类" width="120" align="center">
|
|
|
+ <el-table-column prop="category" label="分类" width="120" align="center" :class-name="sortClass('category')">
|
|
|
<template slot-scope="{ row }">
|
|
|
<el-tag :type="categoryTagType(row.category)" size="mini" effect="plain">
|
|
|
{{ row.category }}
|
|
|
</el-tag>
|
|
|
</template>
|
|
|
+ <template slot="header">
|
|
|
+ <span class="sort-header" @click.stop="onSortClick('category',$event)" @dblclick.stop="onSortToggle('category')">分类{{ sortIcon('category') }}</span>
|
|
|
+ </template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column label="热量" width="100" align="right">
|
|
|
+ <el-table-column label="热量" width="100" align="right" :class-name="sortClass('calories')">
|
|
|
<template slot-scope="{ row }">
|
|
|
<span class="num-val">{{ row.calories != null ? row.calories : '-' }}</span>
|
|
|
<span class="num-unit">kcal</span>
|
|
|
</template>
|
|
|
+ <template slot="header">
|
|
|
+ <span class="sort-header" @click.stop="onSortClick('calories',$event)" @dblclick.stop="onSortToggle('calories')">热量{{ sortIcon('calories') }}</span>
|
|
|
+ </template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column label="蛋白质" width="90" align="right">
|
|
|
+ <el-table-column label="蛋白质" width="90" align="right" :class-name="sortClass('protein')">
|
|
|
<template slot-scope="{ row }">
|
|
|
<span class="num-val">{{ row.protein != null ? row.protein : '-' }}</span>
|
|
|
<span class="num-unit">g</span>
|
|
|
</template>
|
|
|
+ <template slot="header">
|
|
|
+ <span class="sort-header" @click.stop="onSortClick('protein',$event)" @dblclick.stop="onSortToggle('protein')">蛋白{{ sortIcon('protein') }}</span>
|
|
|
+ </template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column label="脂肪" width="80" align="right">
|
|
|
+ <el-table-column label="脂肪" width="80" align="right" :class-name="sortClass('fat')">
|
|
|
<template slot-scope="{ row }">
|
|
|
<span class="num-val">{{ row.fat != null ? row.fat : '-' }}</span>
|
|
|
<span class="num-unit">g</span>
|
|
|
</template>
|
|
|
+ <template slot="header">
|
|
|
+ <span class="sort-header" @click.stop="onSortClick('fat',$event)" @dblclick.stop="onSortToggle('fat')">脂肪{{ sortIcon('fat') }}</span>
|
|
|
+ </template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column label="碳水" width="80" align="right">
|
|
|
+ <el-table-column label="碳水" width="80" align="right" :class-name="sortClass('carbs')">
|
|
|
<template slot-scope="{ row }">
|
|
|
<span class="num-val">{{ row.carbs != null ? row.carbs : '-' }}</span>
|
|
|
<span class="num-unit">g</span>
|
|
|
</template>
|
|
|
+ <template slot="header">
|
|
|
+ <span class="sort-header" @click.stop="onSortClick('carbs',$event)" @dblclick.stop="onSortToggle('carbs')">碳水{{ sortIcon('carbs') }}</span>
|
|
|
+ </template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column label="膳食纤维" width="90" align="right">
|
|
|
+ <el-table-column label="膳食纤维" width="90" align="right" :class-name="sortClass('fiber')">
|
|
|
<template slot-scope="{ row }">
|
|
|
<span class="num-val">{{ row.fiber != null ? row.fiber : '-' }}</span>
|
|
|
<span class="num-unit">g</span>
|
|
|
</template>
|
|
|
+ <template slot="header">
|
|
|
+ <span class="sort-header" @click.stop="onSortClick('fiber',$event)" @dblclick.stop="onSortToggle('fiber')">纤维{{ sortIcon('fiber') }}</span>
|
|
|
+ </template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column label="能量(kJ)" width="90" align="right">
|
|
|
+ <el-table-column label="能量(kJ)" width="90" align="right" :class-name="sortClass('energyKj')">
|
|
|
<template slot-scope="{ row }">
|
|
|
<span class="num-val">{{ row.energyKj != null ? row.energyKj : '-' }}</span>
|
|
|
</template>
|
|
|
+ <template slot="header">
|
|
|
+ <span class="sort-header" @click.stop="onSortClick('energyKj',$event)" @dblclick.stop="onSortToggle('energyKj')">能量{{ sortIcon('energyKj') }}</span>
|
|
|
+ </template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column label="胆固醇" width="90" align="right">
|
|
|
+ <el-table-column label="胆固醇" width="90" align="right" :class-name="sortClass('cholesterol')">
|
|
|
<template slot-scope="{ row }">
|
|
|
<span v-if="row.cholesterol != null" class="num-val">{{ row.cholesterol }}<span class="num-unit">mg</span></span>
|
|
|
<span v-else>-</span>
|
|
|
</template>
|
|
|
+ <template slot="header">
|
|
|
+ <span class="sort-header" @click.stop="onSortClick('cholesterol',$event)" @dblclick.stop="onSortToggle('cholesterol')">胆固醇{{ sortIcon('cholesterol') }}</span>
|
|
|
+ </template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column prop="status" label="状态" width="80" align="center">
|
|
|
+ <el-table-column prop="status" label="状态" width="80" align="center" :class-name="sortClass('status')">
|
|
|
<template slot-scope="{ row }">
|
|
|
<el-tag :type="row.status === 'active' ? 'success' : 'info'" size="mini" effect="dark">
|
|
|
{{ row.status === 'active' ? '启用' : '停用' }}
|
|
|
</el-tag>
|
|
|
</template>
|
|
|
+ <template slot="header">
|
|
|
+ <span class="sort-header" @click.stop="onSortClick('status',$event)" @dblclick.stop="onSortToggle('status')">状态{{ sortIcon('status') }}</span>
|
|
|
+ </template>
|
|
|
</el-table-column>
|
|
|
<el-table-column label="操作" width="180" fixed="right" align="center">
|
|
|
<template slot-scope="{ row }">
|
|
|
@@ -270,6 +310,12 @@ export default {
|
|
|
'蔬菜', '水果', '水产品', '肉类', '干果',
|
|
|
'主食', '豆类及豆制品', '蛋类', '乳制品', '快餐', '汤'
|
|
|
],
|
|
|
+ sortState: [],
|
|
|
+ sortColLabels: {
|
|
|
+ name: '\u540d\u79f0', category: '\u5206\u7c7b', calories: '\u70ed\u91cf', protein: '\u86cb\u767d',
|
|
|
+ carbs: '\u78b3\u6c34', fat: '\u8102\u80aa', fiber: '\u7ea4\u7ef4', energyKj: '\u80fd\u91cf',
|
|
|
+ starch: '\u6dc0\u7c89', cholesterol: '\u80c6\u56fa\u9187', status: '\u72b6\u6001'
|
|
|
+ },
|
|
|
form: {
|
|
|
name: '',
|
|
|
category: '',
|
|
|
@@ -306,12 +352,11 @@ export default {
|
|
|
async loadList() {
|
|
|
this.loading = true
|
|
|
try {
|
|
|
- const res = await getFoodList({
|
|
|
- page: this.page,
|
|
|
- size: this.size,
|
|
|
- category: this.categoryFilter || undefined,
|
|
|
- keyword: this.keyword || undefined
|
|
|
- })
|
|
|
+ const sortParams = { page: this.page, size: this.size }
|
|
|
+ if (this.categoryFilter) sortParams.category = this.categoryFilter
|
|
|
+ if (this.keyword) sortParams.keyword = this.keyword
|
|
|
+ if (this.sortState.length > 0) sortParams.sort = this.sortState
|
|
|
+ const res = await getFoodList(sortParams)
|
|
|
this.list = res.data && res.data.records || []
|
|
|
this.total = res.data && res.data.total || 0
|
|
|
} catch (e) {
|
|
|
@@ -372,6 +417,54 @@ export default {
|
|
|
this.sortState = []
|
|
|
this.loadList()
|
|
|
},
|
|
|
+ sortClass(col) {
|
|
|
+ const s = this.sortState.find(x => x.column === col)
|
|
|
+ if (!s) return ''
|
|
|
+ return s.order === 'asc' ? 'sort-asc' : 'sort-desc'
|
|
|
+ },
|
|
|
+ sortIcon(col) {
|
|
|
+ const s = this.sortState.find(x => x.column === col)
|
|
|
+ if (!s) return ''
|
|
|
+ return s.order === 'asc' ? ' \u2191' : ' \u2193'
|
|
|
+ },
|
|
|
+ onSortClick(col, event) {
|
|
|
+ if (event.shiftKey) {
|
|
|
+ this.shiftAppendSort(col)
|
|
|
+ } else {
|
|
|
+ this.setPrimarySort(col)
|
|
|
+ }
|
|
|
+ this.loadList()
|
|
|
+ },
|
|
|
+ onSortToggle(col) {
|
|
|
+ const idx = this.sortState.findIndex(s => s.column === col)
|
|
|
+ if (idx >= 0) {
|
|
|
+ this.sortState[idx].order = this.sortState[idx].order === 'asc' ? 'desc' : 'asc'
|
|
|
+ } else {
|
|
|
+ this.sortState = [{ column: col, order: 'asc' }]
|
|
|
+ }
|
|
|
+ this.loadList()
|
|
|
+ },
|
|
|
+ setPrimarySort(col) {
|
|
|
+ const idx = this.sortState.findIndex(s => s.column === col)
|
|
|
+ if (idx >= 0) {
|
|
|
+ const item = this.sortState.splice(idx, 1)[0]
|
|
|
+ this.sortState.unshift(item)
|
|
|
+ } else {
|
|
|
+ this.sortState = [{ column: col, order: 'asc' }]
|
|
|
+ }
|
|
|
+ },
|
|
|
+ shiftAppendSort(col) {
|
|
|
+ const idx = this.sortState.findIndex(s => s.column === col)
|
|
|
+ if (idx >= 0) {
|
|
|
+ this.sortState[idx].order = this.sortState[idx].order === 'asc' ? 'desc' : 'asc'
|
|
|
+ } else if (this.sortState.length < 3) {
|
|
|
+ this.sortState.push({ column: col, order: 'asc' })
|
|
|
+ }
|
|
|
+ },
|
|
|
+ clearSort() {
|
|
|
+ this.sortState = []
|
|
|
+ this.loadList()
|
|
|
+ },
|
|
|
handleSizeChange(val) {
|
|
|
this.size = val
|
|
|
this.page = 1
|
|
|
@@ -524,4 +617,22 @@ export default {
|
|
|
.el-descriptions {
|
|
|
margin-top: 8px;
|
|
|
}
|
|
|
+.sort-header {
|
|
|
+ cursor: pointer;
|
|
|
+ user-select: none;
|
|
|
+ font-weight: 500;
|
|
|
+ font-size: 12px;
|
|
|
+}
|
|
|
+.sort-header:hover {
|
|
|
+ color: #409eff;
|
|
|
+}
|
|
|
+.sort-asc ::v-deep .el-table__header-wrapper th .cell,
|
|
|
+.sort-desc ::v-deep .el-table__header-wrapper th .cell {
|
|
|
+ color: #409eff;
|
|
|
+ font-weight: 600;
|
|
|
+}
|
|
|
+.sort-tag {
|
|
|
+ margin-left: 8px;
|
|
|
+ cursor: pointer;
|
|
|
+}
|
|
|
</style>
|