Accept Merge Request #10: (feature/hant -> develop)

Merge Request: 工人录入

Created By: @todayswind
Accepted By: @todayswind
URL: https://g-bcrc3009.coding.net/p/allocatr/d/allocatr/git/merge/10?initial=true
This commit is contained in:
todayswind 2025-03-10 20:31:59 +08:00 committed by Coding
commit d028613923
8 changed files with 400 additions and 70 deletions

View File

@ -2,7 +2,13 @@
namespace app\admin\controller\workers;
use app\admin\model\AuthGroup;
use app\admin\model\Item;
use app\common\controller\Backend;
use fast\Tree;
use think\Db;
use think\exception\PDOException;
use think\exception\ValidateException;
/**
* 师傅列管理
@ -23,6 +29,30 @@ class Worker extends Backend
parent::_initialize();
$this->model = new \app\admin\model\Worker;
$this->view->assign("statusList", $this->model->getStatusList());
$items = model('item')->getAll();
Tree::instance()->init($items)->icon = ['    ', '    ', '    '];
// dd($ruleList);
$res = Tree::instance()->getTreeList(Tree::instance()->getTreeArray(0), 'title');
foreach ($res as &$v) {
$v = $v->toArray();
$v['state'] = ['selected' => false];
$v['parent'] = $v['pid'] ?: '#';
$v['text'] = $v['title'];
unset($v['pid']);
unset($v['title']);
unset($v['level']);
unset($v['key_word']);
unset($v['sort']);
unset($v['status']);
}
$this->tree = $res;
$this->view->assign("tree", $res);
}
@ -51,14 +81,14 @@ class Worker extends Backend
list($where, $sort, $order, $offset, $limit) = $this->buildparams();
$list = $this->model
->with(['area'])
->where($where)
->order($sort, $order)
->paginate($limit);
->with(['area'])
->where($where)
->order($sort, $order)
->paginate($limit);
foreach ($list as $row) {
}
$result = array("total" => $list->total(), "rows" => $list->items());
@ -68,4 +98,127 @@ class Worker extends Backend
return $this->view->fetch();
}
public function add()
{
if (false === $this->request->isPost()) {
return $this->view->fetch();
}
$params = $this->request->post('row/a');
if (empty($params)) {
$this->error(__('Parameter %s can not be empty', ''));
}
$params = $this->preExcludeFields($params);
if ($this->dataLimit && $this->dataLimitFieldAutoFill) {
$params[$this->dataLimitField] = $this->auth->id;
}
$result = false;
Db::startTrans();
try {
//是否采用模型验证
if ($this->modelValidate) {
$name = str_replace("\\model\\", "\\validate\\", get_class($this->model));
$validate = is_bool($this->modelValidate) ? ($this->modelSceneValidate ? $name . '.add' : $name) : $this->modelValidate;
$this->model->validateFailException()->validate($validate);
}
$result = $this->model->allowField(true)->save($params);
$item_map = model('item')->getAll();
$item_map = array_column($item_map,'level','id');
if ($result) {
$items = explode(',', $params['rules']);
if ($items) {
$insert = [];
foreach ($items as $item) {
$insert [] = [
'worker_id' => $result,
'item_id' => $item,
'item_path_id' => $item_map[$item] ?? 0
];
}
model('WorkerItem')->saveAll($insert);
}
}
Db::commit();
} catch (ValidateException|PDOException|Exception $e) {
Db::rollback();
$this->error($e->getMessage());
}
if ($result === false) {
$this->error(__('No rows were inserted'));
}
$this->success();
}
public function edit($ids = null)
{
if (!$ids) {
if (request()->isPost()){
$ids = input('id');
if (!$ids){
$this->error('缺少订单ID');
}
}else{
$this->error('缺少订单ID');
}
}
// 获取当前ID对应的订单信息
$worker = $this->model->get($ids);
if (!$worker) {
$this->error('订单不存在');
}
// 判断是否为POST请求进行更新操作
if (request()->isPost()) {
// 获取表单提交的数据
$params = input('post.row/a');
$item_map = model('item')->getAll();
$item_map = array_column($item_map,'level','id');
if ($ids) {
$items = explode(',', $params['rules']);
if ($items) {
$insert = [];
foreach ($items as $item) {
$insert [] = [
'worker_id' => $ids,
'item_id' => $item,
'item_path_id' => $item_map[$item] ?? 0
];
}
model('WorkerItem')->where('worker_id',$ids)->delete();
model('WorkerItem')->batchInsert($insert);
}
}
unset($params['rules']);
unset($params['address']);
$worker->save($params);
// 返回成功信息
$this->success('更新成功', 'index');
}
$area_name = model('area')->getNameByCode($worker->area_id);
$worker->area_name = str_replace(',','/',$area_name);
$select_ids = model('WorkerItem')->where('worker_id',$ids)->field('item_id')
->select();
$select_ids = array_column($select_ids,'item_id');
foreach ($this->tree as $index=>$item){
if (in_array($item['parent'],$select_ids)){
$this->tree[$index]['state']['selected'] = true;
}
}
// dd($area_name);
// 将订单数据传递到视图
$this->assign('row', $worker);
$this->assign("tree", $this->tree);
// 渲染编辑页面
return $this->fetch();
}
}

View File

@ -43,6 +43,12 @@ class Item extends Model
return $list[$value] ?? '';
}
public function getAll(){
return $this->where('status',1)
->field('id,pid,level,title,key_word,sort,status')
->select();
}

View File

@ -2,6 +2,8 @@
namespace app\admin\model;
use Exception;
use think\Db;
use think\Model;
use traits\model\SoftDelete;
@ -50,4 +52,57 @@ class Worker extends Model
{
return $this->belongsTo('Area', 'area_id', 'id', [], 'LEFT')->setEagerlyType(0);
}
/**
* 批量插入数据到数据库
*
* @param string $table 数据表名
* @param array $data 待插入的数据
* @param int $batchSize 每次插入的数据量(默认 500
* @return int 成功插入的总行数
* @throws Exception 插入失败时抛出异常
*/
function batchInsert( array $data, int $batchSize = 500): int
{
if (empty($data)) {
throw new Exception('插入数据不能为空');
}
// 提取字段名(确保所有数据的字段一致)
$columns = array_keys($data[0]);
$columnList = implode(', ', $columns);
$placeholders = '(' . implode(', ', array_fill(0, count($columns), '?')) . ')';
$totalInserted = 0;
Db::startTrans();
try {
// 数据分批插入
foreach (array_chunk($data, $batchSize) as $chunk) {
$sql = "INSERT INTO {$this->getTable()} ({$columnList}) VALUES " . implode(', ', array_fill(0, count($chunk), $placeholders));
$stmt = $this->prepare($sql);
// 将数据展开填充
$values = [];
foreach ($chunk as $row) {
$values = array_merge($values, array_values($row));
}
if ($stmt->execute($values)) {
$totalInserted += $stmt->rowCount();
} else {
throw new Exception('批量插入失败');
}
}
Db::commit();
return $totalInserted;
} catch (Exception $e) {
Db::rollback();
throw new Exception('批量插入失败:' . $e->getMessage());
}
}
}

View File

@ -0,0 +1,59 @@
<?php
namespace app\admin\model;
use think\Db;
use think\Model;
use traits\model\SoftDelete;
class WorkerItem extends Model
{
// 表名
protected $name = 'worker_item';
/**
* 批量插入数据到数据库
*
* @param string $table 数据表名
* @param array $data 待插入的数据
* @param int $batchSize 每次插入的数据量(默认 500
* @return int 成功插入的总行数
* @throws Exception 插入失败时抛出异常
*/
function batchInsert( array $data, int $batchSize = 500): int
{
if (empty($data)) {
throw new Exception('插入数据不能为空');
}
// 提取字段名(确保所有数据的字段一致)
$columns = array_keys($data[0]);
$columnList = implode(', ', $columns);
$placeholders = '(' . implode(', ', array_fill(0, count($columns), '?')) . ')';
$totalInserted = 0;
Db::startTrans();
try {
// 数据分批插入
foreach (array_chunk($data, $batchSize) as $chunk) {
$sql = "INSERT INTO {$this->getTable()} ({$columnList}) VALUES " . implode(', ', array_fill(0, count($chunk), $placeholders));
// 将数据展开填充
$values = [];
foreach ($chunk as $row) {
$values = array_merge($values, array_values($row));
}
Db::execute($sql,$values);
}
Db::commit();
return $totalInserted;
} catch (Exception $e) {
Db::rollback();
throw new Exception('批量插入失败:' . $e->getMessage());
}
}
}

View File

@ -6,42 +6,21 @@
<input id="c-name" data-rule="required" class="form-control" name="row[name]" type="text" value="">
</div>
</div>
<input type="hidden" name="row[rules]" />
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Tel')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-tel" data-rule="required" class="form-control" name="row[tel]" type="text" value="">
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label>
<div class="col-xs-12 col-sm-8">
<div class="radio">
{foreach name="statusList" item="vo"}
<label for="row[status]-{$key}"><input id="row[status]-{$key}" name="row[status]" type="radio" value="{$key}" {in name="key" value="1"}checked{/in} /> {$vo}</label>
{/foreach}
</div>
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Area_id')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-area_id" data-rule="required" data-field="short_merge_name" data-source="area/index" class="form-control selectpage" name="row[area_id]" type="text" value="">
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Lng')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-lng" class="form-control" step="0.000001" name="row[lng]" type="number">
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Lat')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-lat" class="form-control" step="0.000001" name="row[lat]" type="number">
<div class='col-xs-12 col-sm-8'>
<input id="c-city" data-rule="required" class="form-control" data-toggle="city-picker" name="row[address]" type="text" value="" />
<input id="area_id" style="display: none" class="form-control" name="row[area_id]" hidden type="text" value="" />
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Deposit_amount')}:</label>
<div class="col-xs-12 col-sm-8">
@ -55,6 +34,16 @@
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Items')}:</label>
<div class="col-xs-12 col-sm-8">
<span class="text-muted"><input type="checkbox" name="" id="checkall" /> <label for="checkall"><span>{:__('Check all')}</span></label></span>
<span class="text-muted"><input type="checkbox" name="" id="expandall" /> <label for="expandall"><span>{:__('Expand all')}</span></label></span>
<div id="treeview"></div>
</div>
</div>
<div class="form-group layer-footer">
<label class="control-label col-xs-12 col-sm-2"></label>
<div class="col-xs-12 col-sm-8">
@ -62,3 +51,6 @@
</div>
</div>
</form>
<script>
var nodeData = {:json_encode($tree); };
</script>

View File

@ -3,73 +3,71 @@
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Name')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-name" data-rule="required" class="form-control" name="row[name]" type="text" value="{$row.name|htmlentities}">
<input id="c-name" data-rule="required" class="form-control" name="row[name]" type="text"
value="{$row.name|htmlentities}">
</div>
</div>
<input type="hidden" name="row[rules]" />
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Tel')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-tel" data-rule="required" class="form-control" name="row[tel]" type="text" value="{$row.tel|htmlentities}">
<input id="c-tel" data-rule="required" class="form-control" name="row[tel]" type="text"
value="{$row.tel|htmlentities}">
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label>
<div class="col-xs-12 col-sm-8">
<div class="radio">
{foreach name="statusList" item="vo"}
<label for="row[status]-{$key}"><input id="row[status]-{$key}" name="row[status]" type="radio" value="{$key}" {in name="key" value="$row.status"}checked{/in} /> {$vo}</label>
{/foreach}
{foreach name="statusList" item="vo"}
<label for="row[status]-{$key}"><input id="row[status]-{$key}" name="row[status]" type="radio"
value="{$key}" {in name="key" value="$row.status" }checked{/in}
/> {$vo}</label>
{/foreach}
</div>
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Area_id')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-area_id" data-rule="required" data-source="area/index" class="form-control selectpage" name="row[area_id]" type="text" value="{$row.area_id|htmlentities}">
</div>
<label class="control-label col-xs-12 col-sm-3">{:__('Area_id')}:</label>
<div class='col-xs-12 col-sm-8'>
<input id="c-city" data-rule="required" class="form-control" data-toggle="city-picker" value="{$row.area_name}"
type="text" name="row[address]"/>
<input id="area_id" style="display: none" class="form-control" name="row[area_id]" hidden type="text"
value="{$row.area_id}"/>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Lng')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-lng" class="form-control" step="0.000001" name="row[lng]" type="number" value="{$row.lng|htmlentities}">
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Lat')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-lat" class="form-control" step="0.000001" name="row[lat]" type="number" value="{$row.lat|htmlentities}">
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Deposit_amount')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-deposit_amount" data-rule="required" class="form-control" step="0.01" name="row[deposit_amount]" type="number" value="{$row.deposit_amount|htmlentities}">
<input id="c-deposit_amount" data-rule="required" class="form-control" step="0.01"
name="row[deposit_amount]" type="number" value="{$row.deposit_amount|htmlentities}">
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Star')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-star" data-rule="required" class="form-control" step="0.1" name="row[star]" type="number" value="{$row.star|htmlentities}">
<input id="c-star" data-rule="required" class="form-control" step="0.1" name="row[star]" type="number"
value="{$row.star|htmlentities}">
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Create_time')}:</label>
<label class="control-label col-xs-12 col-sm-2">{:__('Items')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-create_time" class="form-control datetimepicker" data-date-format="YYYY-MM-DD HH:mm:ss" data-use-current="true" name="row[create_time]" type="text" value="{$row.create_time}">
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Update_time')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-update_time" class="form-control datetimepicker" data-date-format="YYYY-MM-DD HH:mm:ss" data-use-current="true" name="row[update_time]" type="text" value="{$row.update_time}">
<span class="text-muted"><input type="checkbox" name="" id="checkall"/> <label for="checkall"><span>{:__('Check all')}</span></label></span>
<span class="text-muted"><input type="checkbox" name="" id="expandall"/> <label for="expandall"><span>{:__('Expand all')}</span></label></span>
<div id="treeview"></div>
</div>
</div>
<div class="form-group layer-footer">
<label class="control-label col-xs-12 col-sm-2"></label>
<div class="col-xs-12 col-sm-8">
<button type="submit" class="btn btn-primary btn-embossed disabled">{:__('OK')}</button>
<button type="submit" class="btn btn-primary btn-embossed">{:__('OK')}</button>
</div>
</div>
</form>
<script>
var nodeData = {:json_encode($tree);}
;
</script>

View File

@ -188,8 +188,9 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
var code = citypicker.getCode("district") || citypicker.getCode("city") || citypicker.getCode("province");
$("#area_id").val(code);
});
$("#c-city").on("click", function() {
Form.api.submit($("form[role=form]"),);
$("#mybuttom").on("click", function() {
Form.api.submit($("form[role=form]"));
Toastr.success('录入成功');
return false;
});
Controller.api.bindevent();

View File

@ -1,5 +1,19 @@
define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) {
define(['jquery', 'bootstrap', 'backend', 'table', 'form','jstree'], function ($, undefined, Backend, Table, Form) {
$.jstree.core.prototype.get_all_checked = function (full) {
var obj = this.get_selected(), i, j;
for (i = 0, j = obj.length; i < j; i++) {
obj = obj.concat(this.get_node(obj[i]).parents);
}
obj = $.grep(obj, function (v, i, a) {
return v != '#';
});
obj = obj.filter(function (itm, i, a) {
return i == a.indexOf(itm);
});
return full ? $.map(obj, $.proxy(function (i) {
return this.get_node(i);
}, this)) : obj;
};
var Controller = {
index: function () {
// 初始化表格参数配置
@ -50,6 +64,12 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
Table.api.bindevent(table);
},
add: function () {
$("#c-city").on("cp:updated", function() {
var citypicker = $(this).data("citypicker");
var code = citypicker.getCode("district") || citypicker.getCode("city") || citypicker.getCode("province");
$("#area_id").val(code);
});
Controller.api.bindevent();
},
edit: function () {
@ -57,7 +77,53 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
},
api: {
bindevent: function () {
Form.api.bindevent($("form[role=form]"));
Form.api.bindevent($("form[role=form]"),null,null,function () {
if ($("#treeview").length > 0) {
var r = $("#treeview").jstree("get_all_checked");
$("input[name='row[rules]']").val(r.join(','));
}
return true;
});
//渲染权限节点树
//销毁已有的节点树
$("#treeview").jstree("destroy");
Controller.api.rendertree(nodeData);
//全选和展开
$(document).on("click", "#checkall", function () {
$("#treeview").jstree($(this).prop("checked") ? "check_all" : "uncheck_all");
});
$(document).on("click", "#expandall", function () {
$("#treeview").jstree($(this).prop("checked") ? "open_all" : "close_all");
});
$("select[name='row[pid]']").trigger("change");
},
rendertree: function (content) {
$("#treeview")
.on('redraw.jstree', function (e) {
$(".layer-footer").attr("domrefresh", Math.random());
})
.jstree({
"themes": {"stripes": true},
"checkbox": {
"keep_selected_style": false,
},
"types": {
"root": {
"icon": "fa fa-folder-open",
},
"menu": {
"icon": "fa fa-folder-open",
},
"file": {
"icon": "fa fa-file-o",
}
},
"plugins": ["checkbox", "types"],
"core": {
'check_callback': true,
"data": content
}
});
}
}
};