Accept Merge Request #57: (feature/zy -> develop)

Merge Request: feature: 面板

Created By: @zhuyu
Accepted By: @zhuyu
URL: https://g-bcrc3009.coding.net/p/allocatr/d/allocatr/git/merge/57
This commit is contained in:
zhuyu 2025-05-22 18:01:21 +08:00 committed by Coding
commit 531edc68c3
21 changed files with 417 additions and 19 deletions

View File

@ -3,6 +3,8 @@
namespace app\admin\controller;
use app\admin\model\Admin;
use app\admin\model\kpi\Template;
use app\admin\model\oa\Task;
use app\admin\model\User;
use app\common\controller\Backend;
use app\common\model\Attachment;
@ -105,7 +107,73 @@ class Dashboard extends Backend
return $this->view->fetch();
}
public function task()
{
$dayTasks = (new Task())
->where('exec_admin_id','=',$this->auth->id)
->where('type','=',1)
->select();
$weekTasks = (new Task())
->where('exec_admin_id','=',$this->auth->id)
->where('type','=',2)
->select();
$monthTasks = (new Task())
->where('exec_admin_id','=',$this->auth->id)
->where('type','=',3)
->select();
$this->view->assign('day', $dayTasks);
$this->view->assign('week', $weekTasks);
$this->view->assign('month', $monthTasks);
return $this->view->fetch();
}
public function kpi()
{
$groupIds = $this->auth->getGroupIds();
$groupId = $groupIds[0] ?? 0;
$kpiTemplate = (new Template())
->where('group_id','=', 6)
->with('kpiitem')
->find();
$kpiItems = $kpiTemplate['kpiitem'];
$this->view->assign('kpi_template', $kpiTemplate);
$this->view->assign('kpi_items', $kpiItems);
return $this->view->fetch();
}
public function task_complete($ids = null)
{
$row = (new Task())->get($ids);
if (!$row) {
$this->error(__('No Results were found'));
}
if (false === $this->request->isPost()) {
$this->view->assign('row', $row);
return $this->view->fetch();
}
$params = $this->request->post('row/a');
$task = (new Task())->where('id', '=', $ids)->where('status', 1)->find();
if (!$task) {
$this->error('任务状态已变更,请刷新后操作');
}
$task->save(['status' => 3, 'prove_file_path' => $params['prove_file_path']]);
$this->success();
}
}

View File

@ -136,7 +136,12 @@ class Template extends Backend
$templateItem = [];
$kpiItems = json_decode($params['kpiitem'], true);
$kpiItemIds = array_column($kpiItems, 'id');
if (count($kpiItemIds) !== count(array_unique($kpiItemIds))) {
throw new Exception('指标有重复项');
}
$rateAll = 0;
foreach ($kpiItems as $kpiItem) {
$templateItem[] = [
'admin_id' => $this->auth->id,
@ -144,6 +149,10 @@ class Template extends Backend
'item_id' => $kpiItem['id'],
'rate' => $kpiItem['rate'],
];
$rateAll += $kpiItem['rate'];
}
if ($rateAll != 100) {
throw new Exception('指标权重总和必须为100');
}
Db::name('kpi_template_item')
@ -216,7 +225,12 @@ class Template extends Backend
$templateItem = [];
$kpiItems = json_decode($params['kpiitem'], true);
$kpiItemIds = array_column($kpiItems, 'id');
if (count($kpiItemIds) !== count(array_unique($kpiItemIds))) {
throw new Exception('指标有重复项');
}
$rateAll = 0;
foreach ($kpiItems as $kpiItem) {
$templateItem[] = [
'admin_id' => $this->auth->id,
@ -224,6 +238,11 @@ class Template extends Backend
'item_id' => $kpiItem['id'],
'rate' => $kpiItem['rate'],
];
$rateAll += $kpiItem['rate'];
}
if ($rateAll != 100) {
throw new Exception('指标权重总和必须为100');
}
Db::name('kpi_template_item')

View File

@ -88,11 +88,34 @@ class Doc extends Backend
->whereRaw('JSON_OVERLAPS(group_ids, ?)', [json_encode($this->auth->getChildrenGroupIds(true))])
->order($sort, $order)
->paginate($limit);
foreach ($list as $k => $row) {
$list[$k]['url'] = cdnurl($row['path']);
}
$result = ['total' => $list->total(), 'rows' => $list->items()];
return json($result);
}
public function detail($ids)
{
$row = $this->model->get(['id' => $ids]);
if (!$row) {
$this->error(__('No Results were found'));
}
if ($this->request->isAjax()) {
$this->success("Ajax请求成功", null, ['id' => $ids]);
}
$row['url'] = cdnurl($row['path']);
$this->view->assign("row", $row->toArray());
return $this->view->fetch();
}
/**
* 添加
*

View File

@ -93,7 +93,13 @@ class Schedule extends Backend
}
$res = [];
$admins = Db::name('admin')->field('id,nickname')->select();
if (!$this->auth->isSuperAdmin()) {
$admins = Db::name('admin')->where('id', $this->auth->id)->field('id,nickname')->select();
} else{
$admins = Db::name('admin')->field('id,nickname')->select();
}
$admins = array_column($admins, NULL, 'id');
$adminIds = array_keys($admins);
@ -111,19 +117,25 @@ class Schedule extends Backend
$res[$adminId][$tmpDate] = '无';
$res[$adminId]['admin_id'] = $adminId;
$res[$adminId]['name'] = $adminNames[$adminId];
$res[$adminId]['editable'] = $this->auth->isSuperAdmin() ? 1 : 0;
}
$dates[] = $tmpDate;
$tmpDate = date('Y-m-d', strtotime($tmpDate) + 86400);
}
$queryData = $this->model
$builder = $this->model
->with([
'admin'
])
->where('date', '>=', $startDate)
->where('date', '<=', $endDate)
->select();
->where('date', '<=', $endDate);
if (!$this->auth->isSuperAdmin()) {
$builder = $builder->where('exec_admin_id', $this->auth->id);
}
$queryData = $builder->select();
foreach ($queryData as $queryDatum) {
$queryDatum = $queryDatum->toArray();

View File

@ -114,6 +114,7 @@ class Task extends Backend
}
$this->assignconfig("review", $this->auth->check("oa/task/review"));
$this->assignconfig("detail", $this->auth->check("oa/task/detail"));
return $this->view->fetch();
}

View File

@ -13,6 +13,8 @@ return [
'Unit 1' => '%',
'Unit 2' => '元',
'Unit 3' => '单',
'Unit 4' => '个',
'Unit 5' => '小时',
'Create_time' => '创建时间',
'Update_time' => '编辑时间'
];

View File

@ -8,6 +8,7 @@ return [
'Name' => '名称',
'Desc' => '描述',
'Score' => '单个绩点分',
'Max_score' => '最高得分上限',
'Create_time' => '创建时间',
'Update_time' => '编辑时间'
];

View File

@ -41,7 +41,7 @@ class Item extends Model
public function getUnitList()
{
return ['1' => __('Unit 1'), '2' => __('Unit 2'), '3' => __('Unit 3')];
return ['1' => __('Unit 1'), '2' => __('Unit 2'), '3' => __('Unit 3'), '4' => __('Unit 4'), '5' => __('Unit 5')];
}

View File

@ -0,0 +1,33 @@
<style>
</style>
<div class="row">
<h2>{$kpi_template->name|htmlentities}</h2>
</div>
<table class="table table-striped">
<thead>
<tr>
<th>指标名称</th>
<th>目标值</th>
<th>目标值(单位)</th>
<th>指标描述</th>
<th>权重</th>
</tr>
</thead>
<tbody>
{foreach $kpi_items as $key => $item}
<tr>
<td>{$item->name|htmlentities}</td>
<td>{$item->target_value|htmlentities}</td>
<td>{$item->unit_text|htmlentities}</td>
<td>{$item->desc|htmlentities}</td>
<td>{$item->pivot->rate|htmlentities}</td>
</tr>
{/foreach}
</tbody>
</table>
<div class="row">
</div>

View File

@ -0,0 +1,114 @@
<style>
.dashboard {
display: grid;
grid-template-columns: repeat(3, 1fr); /* 三列 */
gap: 32px;
width: 1200px; /* 根据需要调整 */
}
/* 每一类任务(每日/每周/每月) */
.section {
display: flex;
flex-direction: column;
gap: 16px;
}
/* 标题部分 */
.section-title {
font-size: 18px;
font-weight: 600;
display: flex;
align-items: center;
gap: 6px;
color: #333;
}
.section-title::before {
content: "📌";
font-size: 20px;
}
/* 卡片样式 */
.card {
background: #fff;
border: 1px solid #e0e4e8;
border-radius: 6px;
padding: 16px 20px;
box-shadow: 0 2px 4px rgba(0, 0, 0, .04);
display: flex;
flex-direction: column;
gap: 8px;
transition: transform .15s ease, box-shadow .15s ease;
}
.card:hover {
transform: translateY(-2px);
box-shadow: 0 6px 12px rgba(0, 0, 0, .08);
}
/* 卡片内标题和注释 */
.card .title {
font-size: 15px;
font-weight: 600;
color: #222;
line-height: 1.45;
}
.card .note {
font-size: 13px;
color: #666;
line-height: 1.4;
}
/* 响应式小屏变成1列 */
@media (max-width: 1024px) {
.dashboard {
grid-template-columns: repeat(2, 1fr);
}
}
@media (max-width: 768px) {
.dashboard {
grid-template-columns: 1fr;
}
}
</style>
<div>
<h2>任务看板</h2>
</div>
<div class="dashboard">
<!-- 每日任务 -->
<div class="section">
<h3 class="section-title">每日任务</h3>
{foreach $day as $item}
<div class="card spec_add_btn" data-url="/admin/dashboard/task_complete/ids/{$item->id}">
<div class="title">{$item->title}</div>
<div class="note">{$item->desc}</div>
</div>
{/foreach}
</div>
<!-- 每周任务 -->
<div class="section">
<h3 class="section-title">每周任务</h3>
{foreach $week as $item}
<div class="card spec_add_btn" data-url="/admin/dashboard/task_complete/ids/{$item->id}">
<div class="title">{$item->title}</div>
<div class="note">{$item->desc}</div>
</div>
{/foreach}
</div>
<!-- 每月任务(举例) -->
<div class="section">
<h3 class="section-title">每月任务</h3>
{foreach $month as $item}
<div class="card spec_add_btn" data-url="/admin/dashboard/task_complete/ids/{$item->id}">
<div class="title">{$item->title}</div>
<div class="note">{$item->desc}</div>
</div>
{/foreach}
</div>
</div>

View File

@ -0,0 +1,38 @@
<form id="task_complete-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action="">
<h1>任务详情</h1>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">标题:</label>
<div class="col-xs-12 col-sm-8">
{$row->title|htmlentities}
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">描述:</label>
<div class="col-xs-12 col-sm-8">
{$row->desc|htmlentities}
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-3">文件地址</label>
<div class="col-xs-12">
<div class="input-group">
<input id="c-prove_file_path" class="form-control" size="50" name="row[prove_file_path]" type="text" value="">
<div class="input-group-addon no-border no-padding">
<span><button type="button" id="plupload-path" class="btn btn-danger plupload" data-input-id="c-prove_file_path" data-mimetype="*" data-multiple="true" data-preview-id="p-path"><i class="fa fa-upload"></i> {:__('Upload')}</button></span>
<span><button type="button" id="fachoose-path" class="btn btn-primary fachoose" data-input-id="c-prove_file_path" data-mimetype="*" data-multiple="true"><i class="fa fa-list"></i> {:__('Choose')}</button></span>
</div>
<span class="msg-box n-right" for="c-prove_file_path"></span>
</div>
</div>
</div>
<div class="form-group layer-footer">
<div class="col-xs-12 col-sm-8">
<button type="submit" class="btn btn-primary btn-embossed disabled">完成任务</button>
<button type="reset" class="btn btn-primary btn-embossed btn-close" onclick="Layer.closeAll();">{:__('Close')}</button>
</div>
</div>
</form>

View File

@ -24,6 +24,12 @@
<input id="c-score" data-rule="required" class="form-control" name="row[score]" type="number" value="0">
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Max_score')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-max_score" data-rule="required" class="form-control" name="row[max_score]" type="number" value="0">
</div>
</div>
<div class="form-group row">
<div class="col-xs-12">
<table class="table fieldlist" data-template="kpiitemtpl" data-name="row[kpiitem]" id="fieldlist-table">

View File

@ -24,6 +24,12 @@
<input id="c-score" data-rule="required" class="form-control" name="row[score]" type="number" value="{$row.score|htmlentities}">
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Max_score')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-max_score" data-rule="required" class="form-control" name="row[max_score]" type="number" value="{$row.max_score|htmlentities}">
</div>
</div>
<div class="form-group row">
<div class="col-xs-12">
<table class="table fieldlist" data-template="kpiitemtpl" data-name="row[kpiitem]" id="fieldlist-table">

View File

@ -33,16 +33,15 @@
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-3">{:__('Path')}:</label>
<div class="col-xs-12 col-sm-8">
<div class="col-xs-12">
<div class="input-group">
<input id="c-path" class="form-control" size="50" name="row[path]" type="text">
<input id="c-path" data-rule="required" class="form-control" size="50" name="row[path]" type="text" value="">
<div class="input-group-addon no-border no-padding">
<span><button type="button" id="faupload-path" class="btn btn-danger faupload" data-input-id="c-path" data-mimetype="image/gif,image/jpeg,image/png,image/jpg,image/bmp,image/webp" data-multiple="true" data-preview-id="p-path"><i class="fa fa-upload"></i> {:__('Upload')}</button></span>
<span><button type="button" id="fachoose-path" class="btn btn-primary fachoose" data-input-id="c-path" data-mimetype="image/*" data-multiple="true"><i class="fa fa-list"></i> {:__('Choose')}</button></span>
<span><button type="button" id="plupload-path" class="btn btn-danger plupload" data-input-id="c-path" data-mimetype="*" data-multiple="true" data-preview-id="p-path"><i class="fa fa-upload"></i> {:__('Upload')}</button></span>
<span><button type="button" id="fachoose-path" class="btn btn-primary fachoose" data-input-id="c-path" data-mimetype="*" data-multiple="true"><i class="fa fa-list"></i> {:__('Choose')}</button></span>
</div>
<span class="msg-box n-right" for="c-path"></span>
</div>
<ul class="row list-inline faupload-preview" id="p-path"></ul>
</div>
</div>
<div class="form-group layer-footer">

View File

@ -0,0 +1,23 @@
{if $row.type == '1'}
<div>
<video controls>
<source src="{$row.url}" type="video/mp4">
</video>
</div>
{/if}
{if $row.type == '2'}
<div>
<img src="{$row.url}" alt="">
</div>
{/if}
{if $row.type == '3'}
<div>
<a href="{$row.url}" target="_blank">点击下载</a>
</div>
{/if}
<div class="hide layer-footer">
<label class="control-label col-xs-12 col-sm-2"></label>
<div class="col-xs-12 col-sm-8">
<button type="reset" class="btn btn-primary btn-embossed btn-close" onclick="Layer.closeAll();">{:__('Close')}</button>
</div>
</div>

View File

@ -33,16 +33,15 @@
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Path')}:</label>
<div class="col-xs-12 col-sm-8">
<div class="col-xs-12">
<div class="input-group">
<input id="c-path" class="form-control" size="50" name="row[path]" type="text" value="{$row.path|htmlentities}">
<input id="c-path" data-rule="required" class="form-control" size="50" name="row[path]" type="text" value="{$row.path|htmlentities}">
<div class="input-group-addon no-border no-padding">
<span><button type="button" id="faupload-path" class="btn btn-danger faupload" data-input-id="c-path" data-mimetype="image/gif,image/jpeg,image/png,image/jpg,image/bmp,image/webp" data-multiple="true" data-preview-id="p-path"><i class="fa fa-upload"></i> {:__('Upload')}</button></span>
<span><button type="button" id="fachoose-path" class="btn btn-primary fachoose" data-input-id="c-path" data-mimetype="image/*" data-multiple="true"><i class="fa fa-list"></i> {:__('Choose')}</button></span>
<span><button type="button" id="plupload-path" class="btn btn-danger plupload" data-input-id="c-path" data-mimetype="*" data-multiple="true" data-preview-id="p-path"><i class="fa fa-upload"></i> {:__('Upload')}</button></span>
<span><button type="button" id="fachoose-path" class="btn btn-primary fachoose" data-input-id="c-path" data-mimetype="*" data-multiple="true"><i class="fa fa-list"></i> {:__('Choose')}</button></span>
</div>
<span class="msg-box n-right" for="c-path"></span>
</div>
<ul class="row list-inline faupload-preview" id="p-path"></ul>
</div>
</div>
<div class="form-group layer-footer">

View File

@ -1,4 +1,4 @@
define(['jquery', 'bootstrap', 'backend', 'addtabs', 'table', 'echarts', 'echarts-theme', 'template'], function ($, undefined, Backend, Datatable, Table, Echarts, undefined, Template) {
define(['jquery', 'bootstrap', 'backend', 'addtabs', 'table', 'echarts', 'echarts-theme', 'template', 'form'], function ($, undefined, Backend, Datatable, Table, Echarts, undefined, Template, Form) {
var Controller = {
index: function () {
@ -73,6 +73,36 @@ define(['jquery', 'bootstrap', 'backend', 'addtabs', 'table', 'echarts', 'echart
}, 0);
});
},
task: function () {
$(document).on('click','.spec_add_btn', function (event) {
var url = $(this).attr('data-url');
if(!url) return false;
var msg = $(this).attr('data-title');
var width = $(this).attr('data-width');
var height = $(this).attr('data-height');
var area = [$(window).width() > 800 ? (width?width:'800px') : '95%', $(window).height() > 600 ? (height?height:'600px') : '95%'];
var options = {
shadeClose: false,
shade: [0.3, '#393D49'],
area: area,
callback:function(value){
CallBackFun(value.id, value.name);//在回调函数里可以调用你的业务代码实现前端的各种逻辑和效果
}
};
Fast.api.open(url,msg,options);
});
},
task_complete: function () {
Form.api.bindevent($("form[role=form]"), function(data, ret){
//这里是表单提交处理成功后的回调函数接收来自php的返回数据
Fast.api.close(data);//这里是重点
Toastr.success("成功");//这个可有可无
}, function(data, ret){
Toastr.success("失败");
});
}
};

View File

@ -31,7 +31,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
{field: 'name', title: __('Name'), operate: 'LIKE'},
{field: 'desc', title: __('Desc'), operate: 'LIKE', table: table, class: 'autocontent', formatter: Table.api.formatter.content},
{field: 'target_value', title: __('Target_value')},
{field: 'unit', title: __('Unit'), searchList: {"1":__('Unit 1'),"2":__('Unit 2'),"3":__('Unit 3')}, formatter: Table.api.formatter.normal},
{field: 'unit', title: __('Unit'), searchList: {"1":__('Unit 1'),"2":__('Unit 2'),"3":__('Unit 3'),"4":__('Unit 4'),"5":__('Unit 5')}, formatter: Table.api.formatter.normal},
{field: 'score', title: __('Score')},
{field: 'create_time', title: __('Create_time'), operate:'RANGE', addclass:'datetimerange', autocomplete:false},
{field: 'update_time', title: __('Update_time'), operate:'RANGE', addclass:'datetimerange', autocomplete:false},

View File

@ -42,6 +42,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
}
},
{field: 'score', title: __('Score')},
{field: 'max_score', title: __('Max_score')},
{field: 'create_time', title: __('Create_time'), operate:'RANGE', addclass:'datetimerange', autocomplete:false},
{field: 'update_time', title: __('Update_time'), operate:'RANGE', addclass:'datetimerange', autocomplete:false},
{field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate}

View File

@ -33,7 +33,23 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
{field: 'path', title: __('Path'), operate: 'LIKE', table: table, class: 'autocontent', formatter: Table.api.formatter.content},
{field: 'create_time', title: __('Create_time'), operate:'RANGE', addclass:'datetimerange', autocomplete:false},
{field: 'update_time', title: __('Update_time'), operate:'RANGE', addclass:'datetimerange', autocomplete:false},
{field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate}
{field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate,
buttons:[
{
name: 'detail',
title: __('查看详情'),
classname: 'btn btn-xs btn-primary btn-dialog',
icon: 'fa fa-list',
url: 'oa/doc/detail',
visible:function(row){
if (!Config.detail) {
return false;
}
return true;
}
}
]
}
]
]
});

View File

@ -86,7 +86,14 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'editable'], function
{value: '中班', text: '中班'},
{value: '晚班', text: '晚班'},
{value: '行政班', text: '行政班'},
]
],
noeditFormatter: function (value, row, index) {
if (row.editable === 1) {
return false;
} else {
return value;
}
},
}
});
}