|
@@ -9,7 +9,7 @@
|
|
|
|
|
|
<div class="search-wrapper">
|
|
<div class="search-wrapper">
|
|
<el-input
|
|
<el-input
|
|
- v-model="form.snCode"
|
|
|
|
|
|
+ v-model="keyword"
|
|
placeholder="搜索相机SN码"
|
|
placeholder="搜索相机SN码"
|
|
class="search-input"
|
|
class="search-input"
|
|
>
|
|
>
|
|
@@ -26,20 +26,20 @@
|
|
|
|
|
|
<div class="table-content">
|
|
<div class="table-content">
|
|
<el-table
|
|
<el-table
|
|
- :data="tableData"
|
|
|
|
|
|
+ :data="list"
|
|
style="width: 100%"
|
|
style="width: 100%"
|
|
stripe
|
|
stripe
|
|
border
|
|
border
|
|
v-loading="loading"
|
|
v-loading="loading"
|
|
>
|
|
>
|
|
<el-table-column
|
|
<el-table-column
|
|
- prop="packageName"
|
|
|
|
|
|
+ prop="id"
|
|
label="会员权益ID"
|
|
label="会员权益ID"
|
|
width="180"
|
|
width="180"
|
|
align="center"
|
|
align="center"
|
|
>
|
|
>
|
|
<template #default="{ row }">
|
|
<template #default="{ row }">
|
|
- <span>{{ row.packageName || '--' }}</span>
|
|
|
|
|
|
+ <span>{{ row.id || '--' }}</span>
|
|
</template>
|
|
</template>
|
|
</el-table-column>
|
|
</el-table-column>
|
|
|
|
|
|
@@ -50,31 +50,66 @@
|
|
align="center"
|
|
align="center"
|
|
>
|
|
>
|
|
<template #default="{ row }">
|
|
<template #default="{ row }">
|
|
- <span>{{ row.snCode || '未绑定' }}</span>
|
|
|
|
|
|
+ <span>{{ row.snCode || '-' }}</span>
|
|
</template>
|
|
</template>
|
|
</el-table-column>
|
|
</el-table-column>
|
|
|
|
|
|
<el-table-column
|
|
<el-table-column
|
|
- prop="buyDate"
|
|
|
|
|
|
+ prop="incrementStartStr"
|
|
label="购买日期"
|
|
label="购买日期"
|
|
width="150"
|
|
width="150"
|
|
align="center"
|
|
align="center"
|
|
>
|
|
>
|
|
<template #default="{ row }">
|
|
<template #default="{ row }">
|
|
- <span>{{ row.buyDate || '--' }}</span>
|
|
|
|
|
|
+ <span>{{ row.incrementStartStr || '--' }}</span>
|
|
</template>
|
|
</template>
|
|
</el-table-column>
|
|
</el-table-column>
|
|
|
|
|
|
<el-table-column
|
|
<el-table-column
|
|
- prop="expiredDate"
|
|
|
|
|
|
+ prop="incrementEndStr"
|
|
label="到期日期"
|
|
label="到期日期"
|
|
width="150"
|
|
width="150"
|
|
align="center"
|
|
align="center"
|
|
>
|
|
>
|
|
<template #default="{ row }">
|
|
<template #default="{ row }">
|
|
- <span :class="{ 'is-expired': isExpired(row.expiredDate) }">
|
|
|
|
- {{ row.expiredDate || '--' }}
|
|
|
|
- </span>
|
|
|
|
|
|
+ <div v-if="row.isExpire" class="is-expired">
|
|
|
|
+ {{ $t("manage.information.memberTable.isExpired") }}
|
|
|
|
+ </div>
|
|
|
|
+ <div v-else class="expired-icon-l">
|
|
|
|
+ {{row.incrementEndStr}}
|
|
|
|
+ <h-icon
|
|
|
|
+ type="register_agreement"
|
|
|
|
+ class="expired-icon"
|
|
|
|
+ v-if="isWillExpired(row)"
|
|
|
|
+ @click.stop="setTimeoutShowCtrls(true, row)"
|
|
|
|
+ ></h-icon>
|
|
|
|
+ <div
|
|
|
|
+ v-show="showCtrls === row.id"
|
|
|
|
+ class="expired-ctrls-w"
|
|
|
|
+ @click.stop
|
|
|
|
+ >
|
|
|
|
+ <p v-if="!expired(row).expiredTime">{{$t('manage.member.memberjtdq')}}</p>
|
|
|
|
+ <p v-else-if="expired(row).trueExpired">
|
|
|
|
+ {{ $t("manage.deviceAdmin.memberExpired") }}
|
|
|
|
+ </p>
|
|
|
|
+ <p
|
|
|
|
+ v-else
|
|
|
|
+ v-html="
|
|
|
|
+ expired(row).expiredTime ? $t('manage.deviceAdmin.memberWillExpired', {
|
|
|
|
+ expired: expired(row).expiredText,
|
|
|
|
+ }) : $t('manage.member.memberjtdq')
|
|
|
|
+ "
|
|
|
|
+ ></p>
|
|
|
|
+ <div class="ctrls-w">
|
|
|
|
+ <div class="btn cancel-btn" @click="showCtrls = null">
|
|
|
|
+ {{ $t("common.cancle") }}
|
|
|
|
+ </div>
|
|
|
|
+ <div class="btn submit-btn" @click="renew(row)">
|
|
|
|
+ {{$t('manage.member.xf')}}
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
</template>
|
|
</template>
|
|
</el-table-column>
|
|
</el-table-column>
|
|
|
|
|
|
@@ -95,7 +130,7 @@
|
|
<el-button
|
|
<el-button
|
|
type="primary"
|
|
type="primary"
|
|
link
|
|
link
|
|
- @click="handleRenew(row)"
|
|
|
|
|
|
+ @click="renew(row)"
|
|
>
|
|
>
|
|
续费
|
|
续费
|
|
</el-button>
|
|
</el-button>
|
|
@@ -119,7 +154,7 @@
|
|
<Paging
|
|
<Paging
|
|
v-if="total"
|
|
v-if="total"
|
|
:total="total"
|
|
:total="total"
|
|
- :current="form.pageNum"
|
|
|
|
|
|
+ :current="pageNum"
|
|
@clickHandle="pageChange"
|
|
@clickHandle="pageChange"
|
|
/>
|
|
/>
|
|
|
|
|
|
@@ -162,78 +197,85 @@
|
|
</template>
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
<script setup>
|
|
-import { ref, reactive, onMounted } from 'vue'
|
|
|
|
|
|
+import { ref, watch, reactive, onMounted, onUnmounted } from 'vue'
|
|
import { ElMessage } from 'element-plus'
|
|
import { ElMessage } from 'element-plus'
|
|
-// import { Search } from '@element-plus/icons-vue'
|
|
|
|
|
|
+import Paging from '@/components/pc/Paging/index.vue'
|
|
|
|
+const emit = defineEmits(['search', 'page-change'])
|
|
|
|
+const props = defineProps({
|
|
|
|
+ list: {
|
|
|
|
+ type: Array,
|
|
|
|
+ default: () => []
|
|
|
|
+ },
|
|
|
|
+ total: {
|
|
|
|
+ type: Number,
|
|
|
|
+ default: 0
|
|
|
|
+ },
|
|
|
|
+ pageNum: {
|
|
|
|
+ type: Number,
|
|
|
|
+ default: 1
|
|
|
|
+ },
|
|
|
|
+ loading: {
|
|
|
|
+ type: Boolean,
|
|
|
|
+ default: false
|
|
|
|
+ },
|
|
|
|
+ snCode: {
|
|
|
|
+ type: String,
|
|
|
|
+ default: ''
|
|
|
|
+ }
|
|
|
|
+})
|
|
|
|
|
|
-// 响应式数据
|
|
|
|
-const tableData = ref([])
|
|
|
|
-const total = ref(0)
|
|
|
|
-const loading = ref(false)
|
|
|
|
|
|
+// UI 状态
|
|
const showBindDialog = ref(false)
|
|
const showBindDialog = ref(false)
|
|
const selectedItem = ref({})
|
|
const selectedItem = ref({})
|
|
const isSearching = ref(false)
|
|
const isSearching = ref(false)
|
|
|
|
+const keyword = ref(props.snCode || '')
|
|
|
|
+const showCtrls = ref(null)
|
|
|
|
+const timer = ref(null)
|
|
|
|
|
|
-const form = reactive({
|
|
|
|
- pageNum: 1,
|
|
|
|
- pageSize: 10,
|
|
|
|
- snCode: ''
|
|
|
|
|
|
+watch(() => props.snCode, (val) => {
|
|
|
|
+ if (val !== keyword.value) keyword.value = val || ''
|
|
})
|
|
})
|
|
|
|
|
|
const bindForm = reactive({
|
|
const bindForm = reactive({
|
|
snCode: ''
|
|
snCode: ''
|
|
})
|
|
})
|
|
-
|
|
|
|
-// 方法
|
|
|
|
-const getTableList = () => {
|
|
|
|
- loading.value = true
|
|
|
|
- // 模拟API调用
|
|
|
|
- setTimeout(() => {
|
|
|
|
- // 模拟数据
|
|
|
|
- const mockData = [
|
|
|
|
- {
|
|
|
|
- id: 1,
|
|
|
|
- packageName: '基础套餐',
|
|
|
|
- snCode: 'SN123456789',
|
|
|
|
- buyDate: '2024-01-15',
|
|
|
|
- expiredDate: '2024-12-15'
|
|
|
|
- },
|
|
|
|
- {
|
|
|
|
- id: 2,
|
|
|
|
- packageName: '高级套餐',
|
|
|
|
- snCode: '',
|
|
|
|
- buyDate: '2024-02-20',
|
|
|
|
- expiredDate: '2024-11-20'
|
|
|
|
- },
|
|
|
|
- {
|
|
|
|
- id: 3,
|
|
|
|
- packageName: '专业套餐',
|
|
|
|
- snCode: 'SN987654321',
|
|
|
|
- buyDate: '2023-12-10',
|
|
|
|
- expiredDate: '2024-01-10'
|
|
|
|
- }
|
|
|
|
- ]
|
|
|
|
-
|
|
|
|
- tableData.value = mockData
|
|
|
|
- total.value = mockData.length
|
|
|
|
- loading.value = false
|
|
|
|
- }, 1000)
|
|
|
|
|
|
+const isWillExpired = (item) => {
|
|
|
|
+ return new Date(item.incrementEndStr) - new Date() <= 86400000 * 30
|
|
}
|
|
}
|
|
|
|
|
|
-const handleKeywordSearch = () => {
|
|
|
|
- form.pageNum = 1
|
|
|
|
- isSearching.value = !!form.snCode
|
|
|
|
- getTableList()
|
|
|
|
|
|
+const expired = (item) => {
|
|
|
|
+ if (!item.incrementEndStr) {
|
|
|
|
+ return {}
|
|
|
|
+ }
|
|
|
|
+ let expired =
|
|
|
|
+ Math.floor((new Date(item.incrementEndStr) - new Date()) / 86400000) + 1
|
|
|
|
+
|
|
|
|
+ return {
|
|
|
|
+ expiredTime: expired,
|
|
|
|
+ expiredText: `<span class="expired" style="color: #ff3e3e">${expired}</span>`,
|
|
|
|
+ isExpired: expired <= 30,
|
|
|
|
+ trueExpired: expired < 0
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
-const handleSizeChange = (size) => {
|
|
|
|
- form.pageSize = size
|
|
|
|
- getTableList()
|
|
|
|
|
|
+const setTimeoutShowCtrls = (show, item) => {
|
|
|
|
+ if (timer.value) {
|
|
|
|
+ clearTimeout(timer.value)
|
|
|
|
+ }
|
|
|
|
+ timer.value = setTimeout(() => {
|
|
|
|
+ showCtrls.value = show ? item.id : null
|
|
|
|
+ }, 200)
|
|
}
|
|
}
|
|
|
|
|
|
-const handleCurrentChange = (page) => {
|
|
|
|
- form.pageNum = page
|
|
|
|
- getTableList()
|
|
|
|
|
|
+const renew = (item) => {
|
|
|
|
+ selectedItem.value = item
|
|
|
|
+ ElMessage.info('跳转到续费页面')
|
|
|
|
+ // 这里可以添加路由跳转逻辑
|
|
|
|
+}
|
|
|
|
+// 方法
|
|
|
|
+const handleKeywordSearch = () => {
|
|
|
|
+ isSearching.value = !!keyword.value
|
|
|
|
+ emit('search', keyword.value.trim())
|
|
}
|
|
}
|
|
|
|
|
|
const handleBind = (item) => {
|
|
const handleBind = (item) => {
|
|
@@ -252,28 +294,36 @@ const handleBindConfirm = () => {
|
|
setTimeout(() => {
|
|
setTimeout(() => {
|
|
ElMessage.success('绑定成功')
|
|
ElMessage.success('绑定成功')
|
|
showBindDialog.value = false
|
|
showBindDialog.value = false
|
|
- getTableList()
|
|
|
|
|
|
+ emit('search', keyword.value.trim())
|
|
}, 1000)
|
|
}, 1000)
|
|
}
|
|
}
|
|
|
|
|
|
-const handleRenew = (item) => {
|
|
|
|
- selectedItem.value = item
|
|
|
|
- ElMessage.info('跳转到续费页面')
|
|
|
|
- // 这里可以添加路由跳转逻辑
|
|
|
|
-}
|
|
|
|
|
|
|
|
const goToBuy = () => {
|
|
const goToBuy = () => {
|
|
ElMessage.info('跳转到购买页面')
|
|
ElMessage.info('跳转到购买页面')
|
|
// 这里可以添加路由跳转逻辑
|
|
// 这里可以添加路由跳转逻辑
|
|
}
|
|
}
|
|
|
|
|
|
-const isExpired = (date) => {
|
|
|
|
- if (!date) return false
|
|
|
|
- return new Date(date) < new Date()
|
|
|
|
|
|
+// removed unused isExpired
|
|
|
|
+
|
|
|
|
+const pageChange = (newPage) => {
|
|
|
|
+ emit('page-change', newPage)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// 全局点击事件处理
|
|
|
|
+const handleGlobalClick = () => {
|
|
|
|
+ setTimeoutShowCtrls(false, {})
|
|
}
|
|
}
|
|
|
|
|
|
onMounted(() => {
|
|
onMounted(() => {
|
|
- getTableList()
|
|
|
|
|
|
+ document.documentElement.addEventListener('click', handleGlobalClick)
|
|
|
|
+})
|
|
|
|
+
|
|
|
|
+onUnmounted(() => {
|
|
|
|
+ document.documentElement.removeEventListener('click', handleGlobalClick)
|
|
|
|
+ if (timer.value) {
|
|
|
|
+ clearTimeout(timer.value)
|
|
|
|
+ }
|
|
})
|
|
})
|
|
</script>
|
|
</script>
|
|
|
|
|
|
@@ -378,9 +428,73 @@ onMounted(() => {
|
|
justify-content: center;
|
|
justify-content: center;
|
|
gap: 16px;
|
|
gap: 16px;
|
|
}
|
|
}
|
|
-
|
|
|
|
.is-expired {
|
|
.is-expired {
|
|
- color: #f56c6c;
|
|
|
|
|
|
+ color: #ff0000;
|
|
|
|
+ }
|
|
|
|
+ .expired-icon {
|
|
|
|
+ margin-left: 6px;
|
|
|
|
+ color: #ff0000;
|
|
|
|
+ font-size: 14px;
|
|
|
|
+ cursor: pointer;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .expired-icon-l {
|
|
|
|
+ position: relative;
|
|
|
|
+
|
|
|
|
+ .expired-ctrls-w {
|
|
|
|
+ position: absolute;
|
|
|
|
+ right: 0px;
|
|
|
|
+ background: #fff;
|
|
|
|
+ z-index: 1000;
|
|
|
|
+ min-width: 172px;
|
|
|
|
+ padding: 12px 16px;
|
|
|
|
+ box-shadow: 0px 2px 12px 0px rgba(50, 50, 51, 0.12);
|
|
|
|
+ bottom: -10px;
|
|
|
|
+ transform: translateY(100%);
|
|
|
|
+ border-radius: 4px;
|
|
|
|
+ font-size: 14px;
|
|
|
|
+ color: #323233;
|
|
|
|
+ line-height: 22px;
|
|
|
|
+
|
|
|
|
+ p {
|
|
|
|
+ white-space: nowrap;
|
|
|
|
+ margin: 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ &::before {
|
|
|
|
+ content: "";
|
|
|
|
+ display: block;
|
|
|
|
+ border: 8px solid transparent;
|
|
|
|
+ border-bottom-color: #fff;
|
|
|
|
+ position: absolute;
|
|
|
|
+ top: -15px;
|
|
|
|
+ left: 90px;
|
|
|
|
+ z-index: 1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .ctrls-w {
|
|
|
|
+ display: flex;
|
|
|
|
+ justify-content: flex-end;
|
|
|
|
+ margin-top: 13px;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .btn {
|
|
|
|
+ padding: 0 8px;
|
|
|
|
+ line-height: 24px;
|
|
|
|
+ border-radius: 2px;
|
|
|
|
+ background: #ebebeb;
|
|
|
|
+ display: inline-block;
|
|
|
|
+ cursor: pointer;
|
|
|
|
+ font-size: 12px;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .submit-btn {
|
|
|
|
+ background: #15bec8;
|
|
|
|
+ margin-left: 8px;
|
|
|
|
+ border-radius: 2px;
|
|
|
|
+ color: #fff;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
.pagination {
|
|
.pagination {
|