Commit 5bc183dc authored by 刘小敏's avatar 刘小敏

管理后台用户管理增加生日提醒逻辑

parent 1ce55c68
...@@ -11,4 +11,31 @@ use think\db\Query; ...@@ -11,4 +11,31 @@ use think\db\Query;
class UserFilter extends BaseFilter class UserFilter extends BaseFilter
{ {
protected $keywordFields = ['id', 'username', 'nickname', 'mobile', 'email']; protected $keywordFields = ['id', 'username', 'nickname', 'mobile', 'email'];
/**
* 生日范围查询(date 类型字段)
*/
public function birthday(Query $query, $data)
{
$operator = $this->getOperator($data);
$value = $this->getValue($data);
if ($operator == 'range' || $operator == 'not range') {
$currentValue = explode(' - ', $value);
// 对 date 类型字段去除时间部分
$dateArr = [];
foreach ($currentValue as $v) {
$v = trim($v);
if ($v !== '') {
$dateArr[] = date('Y-m-d', strtotime($v));
}
}
if (count($dateArr) == 1) {
return $query->where('birthday', $operator == 'range' ? '>=' : '<', $dateArr[0]);
} else if (count($dateArr) == 2) {
return $query->whereBetween('birthday', $dateArr);
}
}
return $query;
}
} }
...@@ -64,10 +64,14 @@ class User extends Common ...@@ -64,10 +64,14 @@ class User extends Common
public function edit($id = null) public function edit($id = null)
{ {
operate_filter(); operate_filter();
$params = $this->request->only(['username', 'nickname', 'mobile', 'password', 'avatar', 'gender', 'email', 'status']); $params = $this->request->only(['username', 'nickname', 'mobile', 'password', 'avatar', 'gender', 'email', 'status', 'birthday']);
if (empty($params['password'])) unset($params['password']); if (empty($params['password'])) unset($params['password']);
if (empty($params['username'])) unset($params['username']); if (empty($params['username'])) unset($params['username']);
if (isset($params['birthday']) && trim($params['birthday']) === '') {
$params['birthday'] = null;
}
$params['id'] = $id; $params['id'] = $id;
$this->svalidate($params, '.edit'); $this->svalidate($params, '.edit');
...@@ -200,4 +204,80 @@ class User extends Common ...@@ -200,4 +204,80 @@ class User extends Common
} }
/**
* 导出用户列表(分页多选导出)
*/
public function export()
{
$ids = $this->request->param('ids', '');
if (empty($ids)) {
$this->error('请选择要导出的用户');
}
$idArr = array_filter(array_map('intval', explode(',', $ids)));
if (empty($idArr)) {
$this->error('导出数据为空');
}
$cellTitles = [
'id' => 'ID',
'username' => '用户名',
'nickname' => '昵称',
'mobile' => '手机号',
'email' => '邮箱',
'gender_text' => '性别',
'birthday' => '生日',
'status_text' => '状态',
'commission' => '佣金',
'total_consume' => '总消费',
'score' => '积分',
'money' => '余额',
'createtime' => '注册时间',
'logintime' => '上次登录',
];
$total = count($idArr);
$export = new \addons\shopro\library\Export();
$params = [
'file_name' => '用户列表',
'cell_titles' => $cellTitles,
'total' => $total,
];
$result = $export->export($params, function ($pages) use ($idArr) {
$ids = array_slice($idArr, ($pages['page'] - 1) * $pages['list_rows'], $pages['list_rows']);
$datas = $this->model->with(['shopro_user_tag'])
->where('id', 'in', $ids)
->select();
$datas = collection($datas)->toArray();
$newDatas = [];
foreach ($datas as $user) {
$newDatas[] = [
'id' => $user['id'] ?? '',
'username' => $user['username'] ?? '',
'nickname' => $user['nickname'] ?? '',
'mobile' => $user['mobile'] ?? '',
'email' => $user['email'] ?? '',
'gender_text' => $user['gender_text'] ?? '',
'birthday' => $user['birthday'] ?? '',
'status_text' => $user['status_text'] ?? '',
'commission' => $user['commission'] ?? '',
'total_consume' => $user['total_consume'] ?? '',
'score' => $user['score'] ?? '',
'money' => $user['money'] ?? '',
'createtime' => $user['createtime'] ?? '',
'logintime' => $user['logintime'] ?? '',
];
}
return $newDatas;
});
return $result;
}
} }
...@@ -153,6 +153,10 @@ ...@@ -153,6 +153,10 @@
</el-input> </el-input>
</div> </div>
</el-col> </el-col>
<el-col :xs="24" :sm="12" :md="24" :lg="24" :xl="24">
<div class="left">生日</div>
<div class="right">{{ state.detail.birthday || '-' }}</div>
</el-col>
<!-- 新增用户标签选择器 --> <!-- 新增用户标签选择器 -->
<el-col :xs="24" :sm="12" :md="24" :lg="24" :xl="24"> <el-col :xs="24" :sm="12" :md="24" :lg="24" :xl="24">
......
{include file="/shopro/common/script" /} {include file="/shopro/common/script" /}
<style>
.sa-birthday-soon {
color: #f56c6c;
font-weight: bold;
background: #fef0f0;
padding: 2px 8px;
border-radius: 4px;
}
</style>
<div id="index" class="user-index panel panel-default panel-intro" v-cloak> <div id="index" class="user-index panel panel-default panel-intro" v-cloak>
<el-container class="panel-block"> <el-container class="panel-block">
<el-header class="sa-header"> <el-header class="sa-header">
...@@ -10,13 +20,17 @@ ...@@ -10,13 +20,17 @@
</sa-filter-condition> </sa-filter-condition>
</div> </div>
<div class="sa-title-right"> <div class="sa-title-right">
{if $auth->check('shopro/user/user/export')}
<el-button :loading="exportLoading" :disabled="exportLoading || selectedIds.length === 0" @click="onExport">导出Excel</el-button>
{/if}
<el-button class="sa-button-refresh" icon="RefreshRight" @click="getData"></el-button> <el-button class="sa-button-refresh" icon="RefreshRight" @click="getData"></el-button>
<el-button class="sa-button-refresh" icon="Search" @click="onOpenFilter"></el-button> <el-button class="sa-button-refresh" icon="Search" @click="onOpenFilter"></el-button>
</div> </div>
</div> </div>
</el-header> </el-header>
<el-main class="sa-main"> <el-main class="sa-main">
<el-table height="100%" class="sa-table" :data="state.data" stripe @sort-change="onChangeSort"> <el-table height="100%" class="sa-table" :data="state.data" stripe @sort-change="onChangeSort" @selection-change="onSelectionChange" ref="tableRef">
<el-table-column type="selection" min-width="50"></el-table-column>
<el-table-column prop="id" label="ID" min-width="90" sortable="custom"> </el-table-column> <el-table-column prop="id" label="ID" min-width="90" sortable="custom"> </el-table-column>
<el-table-column label="用户信息" min-width="150"> <el-table-column label="用户信息" min-width="150">
<template #default="scope"> <template #default="scope">
...@@ -37,6 +51,11 @@ ...@@ -37,6 +51,11 @@
</el-table-column> </el-table-column>
<el-table-column sortable="custom" prop="createtime" label="注册时间" min-width="172"></el-table-column> <el-table-column sortable="custom" prop="createtime" label="注册时间" min-width="172"></el-table-column>
<el-table-column sortable="custom" prop="logintime" label="上次登录" min-width="172"></el-table-column> <el-table-column sortable="custom" prop="logintime" label="上次登录" min-width="172"></el-table-column>
<el-table-column prop="birthday" label="生日" min-width="160">
<template #default="scope">
<span :class="{ 'sa-birthday-soon': isBirthdaySoon(scope.row.birthday) }">{{ scope.row.birthday || '-' }}</span>
</template>
</el-table-column>
<el-table-column label="用户标签" min-width="100"> <el-table-column label="用户标签" min-width="100">
<template #default="scope"> <template #default="scope">
<div v-for="item in scope.row.shopro_user_tag" :key="item.tag_code"> <div v-for="item in scope.row.shopro_user_tag" :key="item.tag_code">
......
...@@ -2,7 +2,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin ...@@ -2,7 +2,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
var Controller = { var Controller = {
index: () => { index: () => {
const { reactive, onMounted } = Vue const { reactive, ref, onMounted } = Vue
const index = { const index = {
setup() { setup() {
const state = reactive({ const state = reactive({
...@@ -16,6 +16,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin ...@@ -16,6 +16,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
status: '', status: '',
createtime: [], createtime: [],
logintime: [], logintime: [],
birthday: [],
}, },
tools: { tools: {
user: { user: {
...@@ -82,6 +83,11 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin ...@@ -82,6 +83,11 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
label: '上次登录', label: '上次登录',
value: [], value: [],
}, },
birthday: {
type: 'tdatetimerange',
label: '生日',
value: [],
},
}, },
condition: {}, condition: {},
} }
...@@ -96,6 +102,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin ...@@ -96,6 +102,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
email: 'like', email: 'like',
createtime: 'range', createtime: 'range',
logintime: 'range', logintime: 'range',
birthday: 'range',
}); });
Fast.api.ajax({ Fast.api.ajax({
url: 'shopro/user/user', url: 'shopro/user/user',
...@@ -150,6 +157,43 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin ...@@ -150,6 +157,43 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
}, function (ret, res) { }) }, function (ret, res) { })
} }
/**
* 判断是否距生日还有7天(仅剩7天时高亮)
*/
function isBirthdaySoon(birthday) {
if (!birthday) return false;
let now = new Date();
let birth = new Date(birthday);
// 构造今年的生日日期
let thisYearBirthday = new Date(now.getFullYear(), birth.getMonth(), birth.getDate());
// 如果今年的生日已过,则判断明年的生日
if (thisYearBirthday < now) {
thisYearBirthday = new Date(now.getFullYear() + 1, birth.getMonth(), birth.getDate());
}
let diffDays = Math.ceil((thisYearBirthday - now) / (1000 * 60 * 60 * 24));
return diffDays === 7;
}
const selectedIds = ref([]);
const tableRef = ref(null);
function onSelectionChange(selection) {
selectedIds.value = selection.map(item => item.id);
}
const exportLoading = ref(false);
function onExport() {
if (selectedIds.value.length === 0) {
Fast.api.msg('请先选择要导出的用户');
return;
}
exportLoading.value = true;
let ids = selectedIds.value.join(',');
window.location.href = `${Config.moduleurl}/shopro/user/user/export?ids=${ids}`;
setTimeout(function () {
exportLoading.value = false;
}, 3000);
}
onMounted(() => { onMounted(() => {
getData() getData()
}) })
...@@ -162,7 +206,13 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin ...@@ -162,7 +206,13 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
onChangeFilter, onChangeFilter,
pagination, pagination,
onDetail, onDetail,
onDelete onDelete,
isBirthdaySoon,
selectedIds,
tableRef,
onSelectionChange,
exportLoading,
onExport
} }
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment