mirror of
https://github.com/kuaifan/dootask.git
synced 2026-02-15 12:03:55 +00:00
feat: support configurable default priority
This commit is contained in:
parent
c69123ac92
commit
55303689ea
@ -697,27 +697,16 @@ class SystemController extends AbstractController
|
|||||||
if ($type == 'save') {
|
if ($type == 'save') {
|
||||||
User::auth('admin');
|
User::auth('admin');
|
||||||
$list = Request::input('list');
|
$list = Request::input('list');
|
||||||
$array = [];
|
|
||||||
if (empty($list) || !is_array($list)) {
|
if (empty($list) || !is_array($list)) {
|
||||||
return Base::retError('参数错误');
|
return Base::retError('参数错误');
|
||||||
}
|
}
|
||||||
foreach ($list AS $item) {
|
$array = Setting::normalizeTaskPriorityList($list);
|
||||||
if (empty($item['name']) || empty($item['color']) || empty($item['priority'])) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$array[] = [
|
|
||||||
'name' => $item['name'],
|
|
||||||
'color' => $item['color'],
|
|
||||||
'days' => intval($item['days']),
|
|
||||||
'priority' => intval($item['priority']),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
if (empty($array)) {
|
if (empty($array)) {
|
||||||
return Base::retError('参数为空');
|
return Base::retError('参数为空');
|
||||||
}
|
}
|
||||||
$setting = Base::setting('priority', $array);
|
$setting = Base::setting('priority', $array);
|
||||||
} else {
|
} else {
|
||||||
$setting = Base::setting('priority');
|
$setting = Setting::normalizeTaskPriorityList(Base::setting('priority'));
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
return Base::retSuccess($type == 'save' ? '保存成功' : 'success', $setting);
|
return Base::retSuccess($type == 'save' ? '保存成功' : 'success', $setting);
|
||||||
|
|||||||
@ -418,6 +418,22 @@ class ProjectTask extends AbstractModel
|
|||||||
}
|
}
|
||||||
//
|
//
|
||||||
$retPre = $parent_id ? '子任务' : '任务';
|
$retPre = $parent_id ? '子任务' : '任务';
|
||||||
|
|
||||||
|
// 优先级:主任务在缺省时按系统默认补齐,并尽量补全 name/color
|
||||||
|
if ($parent_id == 0) {
|
||||||
|
$priorityList = Setting::normalizeTaskPriorityList(Base::setting('priority'));
|
||||||
|
if ($p_level > 0) {
|
||||||
|
$matched = reset(array_filter($priorityList, fn($item) => intval($item['priority']) === $p_level)) ?: null;
|
||||||
|
} else {
|
||||||
|
$matched = Setting::getDefaultTaskPriorityItem($priorityList);
|
||||||
|
}
|
||||||
|
if ($matched) {
|
||||||
|
$p_level = $p_level > 0 ? $p_level : intval($matched['priority']);
|
||||||
|
$p_name = $p_name ?: $matched['name'];
|
||||||
|
$p_color = $p_color ?: $matched['color'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$task = self::createInstance([
|
$task = self::createInstance([
|
||||||
'parent_id' => $parent_id,
|
'parent_id' => $parent_id,
|
||||||
'project_id' => $project_id,
|
'project_id' => $project_id,
|
||||||
|
|||||||
@ -106,6 +106,70 @@ class Setting extends AbstractModel
|
|||||||
return $value;
|
return $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 规范任务优先级设置(确保字段完整且仅有一个默认项)
|
||||||
|
* @param mixed $list
|
||||||
|
* @return array<int, array{name:string,color:string,days:int,priority:int,is_default:int}>
|
||||||
|
*/
|
||||||
|
public static function normalizeTaskPriorityList($list)
|
||||||
|
{
|
||||||
|
if (!is_array($list)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
$normalized = [];
|
||||||
|
$defaultIndex = null;
|
||||||
|
foreach ($list as $item) {
|
||||||
|
if (!is_array($item)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$name = trim((string)($item['name'] ?? ''));
|
||||||
|
$color = trim((string)($item['color'] ?? ''));
|
||||||
|
$priority = intval($item['priority'] ?? 0);
|
||||||
|
if ($name === '' || $color === '' || $priority <= 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$days = intval($item['days'] ?? 0);
|
||||||
|
$isDefault = !empty($item['is_default']) || !empty($item['default']);
|
||||||
|
if ($defaultIndex === null && $isDefault) {
|
||||||
|
$defaultIndex = count($normalized);
|
||||||
|
}
|
||||||
|
$normalized[] = [
|
||||||
|
'name' => $name,
|
||||||
|
'color' => $color,
|
||||||
|
'days' => $days,
|
||||||
|
'priority' => $priority,
|
||||||
|
'is_default' => $isDefault ? 1 : 0,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if (!empty($normalized)) {
|
||||||
|
$defaultIndex = $defaultIndex ?? 0;
|
||||||
|
foreach ($normalized as $i => $row) {
|
||||||
|
$normalized[$i]['is_default'] = $i === $defaultIndex ? 1 : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return array_values($normalized);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取默认任务优先级(来自 settings.priority)
|
||||||
|
* @param array|null $list
|
||||||
|
* @return array|null
|
||||||
|
*/
|
||||||
|
public static function getDefaultTaskPriorityItem($list = null)
|
||||||
|
{
|
||||||
|
$list = $list ?? Base::setting('priority');
|
||||||
|
$list = self::normalizeTaskPriorityList($list);
|
||||||
|
if (empty($list)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
foreach ($list as $item) {
|
||||||
|
if (!empty($item['is_default'])) {
|
||||||
|
return $item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $list[0];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否开启 AI 助手
|
* 是否开启 AI 助手
|
||||||
* @return bool
|
* @return bool
|
||||||
|
|||||||
@ -37,7 +37,7 @@ class SettingsTableSeeder extends Seeder
|
|||||||
array (
|
array (
|
||||||
'name' => 'priority',
|
'name' => 'priority',
|
||||||
'desc' => '',
|
'desc' => '',
|
||||||
'setting' => '[{"name":"\\u91cd\\u8981\\u4e14\\u7d27\\u6025","color":"#ED4014","days":1,"priority":1},{"name":"\\u91cd\\u8981\\u4e0d\\u7d27\\u6025","color":"#F16B62","days":3,"priority":2},{"name":"\\u7d27\\u6025\\u4e0d\\u91cd\\u8981","color":"#19C919","days":5,"priority":3},{"name":"\\u4e0d\\u91cd\\u8981\\u4e0d\\u7d27\\u6025","color":"#2D8CF0","days":0,"priority":4}]',
|
'setting' => '[{"name":"\\u91cd\\u8981\\u4e14\\u7d27\\u6025","color":"#ED4014","days":1,"priority":1,"is_default":1},{"name":"\\u91cd\\u8981\\u4e0d\\u7d27\\u6025","color":"#F16B62","days":3,"priority":2,"is_default":0},{"name":"\\u7d27\\u6025\\u4e0d\\u91cd\\u8981","color":"#19C919","days":5,"priority":3,"is_default":0},{"name":"\\u4e0d\\u91cd\\u8981\\u4e0d\\u7d27\\u6025","color":"#2D8CF0","days":0,"priority":4,"is_default":0}]',
|
||||||
'created_at' => seeders_at('2021-07-01 08:04:30'),
|
'created_at' => seeders_at('2021-07-01 08:04:30'),
|
||||||
'updated_at' => seeders_at('2021-07-01 09:20:26'),
|
'updated_at' => seeders_at('2021-07-01 09:20:26'),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -392,7 +392,8 @@ export default {
|
|||||||
}
|
}
|
||||||
// 优先级
|
// 优先级
|
||||||
if (this.taskPriority.length > 0) {
|
if (this.taskPriority.length > 0) {
|
||||||
await this.choosePriority(this.taskPriority[0]);
|
const defaultItem = this.taskPriority.find(item => item.is_default === 1) || this.taskPriority[0];
|
||||||
|
await this.choosePriority(defaultItem);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@ -270,7 +270,8 @@ export default {
|
|||||||
if (this.taskPriority.length === 0 || this.addData.p_name) {
|
if (this.taskPriority.length === 0 || this.addData.p_name) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.choosePriority(this.taskPriority[0], false);
|
const defaultItem = this.taskPriority.find(item => item.is_default === 1) || this.taskPriority[0];
|
||||||
|
this.choosePriority(defaultItem, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="setting-component-item">
|
<div class="setting-component-item system-task-priority">
|
||||||
<Form ref="formDatum" label-width="auto" @submit.native.prevent>
|
<Form ref="formDatum" label-width="auto" @submit.native.prevent>
|
||||||
<Row class="setting-color color-label-box">
|
<Row class="setting-color color-label-box">
|
||||||
<Col span="12">{{$L('名称')}}</Col>
|
<Col span="2">{{$L('默认')}}</Col>
|
||||||
|
<Col span="10">{{$L('名称')}}</Col>
|
||||||
<Col span="4">
|
<Col span="4">
|
||||||
<ETooltip :content="$L('数值越小级别越高')" max-width="auto" placement="top" transfer>
|
<ETooltip :content="$L('数值越小级别越高')" max-width="auto" placement="top" transfer>
|
||||||
<div><Icon class="information" type="ios-information-circle-outline" /> {{$L('级别')}}</div>
|
<div><Icon class="information" type="ios-information-circle-outline" /> {{$L('级别')}}</div>
|
||||||
@ -15,26 +16,33 @@
|
|||||||
</Col>
|
</Col>
|
||||||
<Col span="4">{{$L('颜色')}}</Col>
|
<Col span="4">{{$L('颜色')}}</Col>
|
||||||
</Row>
|
</Row>
|
||||||
<Row v-for="(item, key) in formDatum" :key="key" class="setting-color">
|
<RadioGroup v-model="defaultIndex">
|
||||||
<Col span="12">
|
<Row v-for="(item, key) in formDatum" :key="key" class="setting-color">
|
||||||
<Input
|
<Col span="2" class="priority-default-col">
|
||||||
v-model="item.name"
|
<Radio :label="key"><span></span></Radio>
|
||||||
:maxlength="20"
|
</Col>
|
||||||
:placeholder="$L('请输入名称')"
|
<Col span="10">
|
||||||
clearable
|
<Input
|
||||||
@on-clear="delDatum(key)"/>
|
v-model="item.name"
|
||||||
</Col>
|
:maxlength="20"
|
||||||
<Col span="4">
|
:placeholder="$L('请输入名称')"
|
||||||
<Input v-model="item.priority" type="number"/>
|
clearable
|
||||||
</Col>
|
@on-clear="delDatum(key)"/>
|
||||||
<Col span="4">
|
</Col>
|
||||||
<Input v-model="item.days" type="number"/>
|
<Col span="4">
|
||||||
</Col>
|
<Input v-model="item.priority" type="number"/>
|
||||||
<Col span="4">
|
</Col>
|
||||||
<ColorPicker v-model="item.color" recommend transfer/>
|
<Col span="4">
|
||||||
</Col>
|
<Input v-model="item.days" type="number"/>
|
||||||
</Row>
|
</Col>
|
||||||
<Button type="default" icon="md-add" @click="addDatum">{{$L('添加优先级')}}</Button>
|
<Col span="4">
|
||||||
|
<ColorPicker v-model="item.color" recommend transfer/>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</RadioGroup>
|
||||||
|
<div class="priority-add-action">
|
||||||
|
<Button type="default" icon="md-add" @click="addDatum">{{$L('添加优先级')}}</Button>
|
||||||
|
</div>
|
||||||
</Form>
|
</Form>
|
||||||
<div class="setting-footer">
|
<div class="setting-footer">
|
||||||
<Button :loading="loadIng > 0" type="primary" @click="submitForm">{{$L('提交')}}</Button>
|
<Button :loading="loadIng > 0" type="primary" @click="submitForm">{{$L('提交')}}</Button>
|
||||||
@ -53,12 +61,14 @@ export default {
|
|||||||
loadIng: 0,
|
loadIng: 0,
|
||||||
|
|
||||||
formDatum: [],
|
formDatum: [],
|
||||||
|
defaultIndex: 0,
|
||||||
|
|
||||||
nullDatum: {
|
nullDatum: {
|
||||||
'name': '',
|
'name': '',
|
||||||
'priority': 1,
|
'priority': 1,
|
||||||
'days': 1,
|
'days': 1,
|
||||||
'color': '#84C56A',
|
'color': '#84C56A',
|
||||||
|
'is_default': 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -75,11 +85,17 @@ export default {
|
|||||||
taskPriority: {
|
taskPriority: {
|
||||||
handler(data) {
|
handler(data) {
|
||||||
this.formDatum = $A.cloneJSON(data);
|
this.formDatum = $A.cloneJSON(data);
|
||||||
|
const idx = this.formDatum.findIndex(item => $A.runNum(item.is_default) === 1 || item.is_default === true || item.default);
|
||||||
|
this.defaultIndex = idx > -1 ? idx : 0;
|
||||||
|
this.applyDefaultIndex();
|
||||||
if (this.formDatum.length === 0) {
|
if (this.formDatum.length === 0) {
|
||||||
this.addDatum();
|
this.addDatum();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
immediate: true,
|
immediate: true,
|
||||||
|
},
|
||||||
|
defaultIndex() {
|
||||||
|
this.applyDefaultIndex();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -94,21 +110,40 @@ export default {
|
|||||||
|
|
||||||
resetForm() {
|
resetForm() {
|
||||||
this.formDatum = $A.cloneJSON(this.taskPriority);
|
this.formDatum = $A.cloneJSON(this.taskPriority);
|
||||||
|
const idx = this.formDatum.findIndex(item => $A.runNum(item.is_default) === 1 || item.is_default === true || item.default);
|
||||||
|
this.defaultIndex = idx > -1 ? idx : 0;
|
||||||
|
this.applyDefaultIndex();
|
||||||
},
|
},
|
||||||
|
|
||||||
addDatum() {
|
addDatum() {
|
||||||
this.formDatum.push($A.cloneJSON(this.nullDatum));
|
this.formDatum.push($A.cloneJSON(this.nullDatum));
|
||||||
|
if (this.formDatum.length === 1) {
|
||||||
|
this.defaultIndex = 0;
|
||||||
|
this.applyDefaultIndex();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
delDatum(key) {
|
delDatum(key) {
|
||||||
this.formDatum.splice(key, 1);
|
this.formDatum.splice(key, 1);
|
||||||
if (this.formDatum.length === 0) {
|
if (this.formDatum.length === 0) {
|
||||||
this.addDatum();
|
this.addDatum();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
if (this.defaultIndex >= this.formDatum.length) {
|
||||||
|
this.defaultIndex = 0;
|
||||||
|
}
|
||||||
|
this.applyDefaultIndex();
|
||||||
|
},
|
||||||
|
|
||||||
|
applyDefaultIndex() {
|
||||||
|
this.formDatum.forEach((item, idx) => {
|
||||||
|
item.is_default = idx === this.defaultIndex ? 1 : 0;
|
||||||
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
systemSetting(save) {
|
systemSetting(save) {
|
||||||
this.loadIng++;
|
this.loadIng++;
|
||||||
|
this.applyDefaultIndex();
|
||||||
this.$store.dispatch("call", {
|
this.$store.dispatch("call", {
|
||||||
url: 'system/priority?type=' + (save ? 'save' : 'get'),
|
url: 'system/priority?type=' + (save ? 'save' : 'get'),
|
||||||
method: 'post',
|
method: 'post',
|
||||||
|
|||||||
24
resources/assets/sass/pages/page-setting.scss
vendored
24
resources/assets/sass/pages/page-setting.scss
vendored
@ -190,6 +190,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.setting-color {
|
.setting-color {
|
||||||
|
min-width: 520px;
|
||||||
&.color-label-box {
|
&.color-label-box {
|
||||||
.el-tooltip {
|
.el-tooltip {
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
@ -198,6 +199,29 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.system-task-priority {
|
||||||
|
.setting-color {
|
||||||
|
white-space: nowrap;
|
||||||
|
> div:first-child {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
> div:nth-child(2) {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.priority-default-col {
|
||||||
|
.ivu-radio-wrapper {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
.ivu-radio-wrapper {
|
||||||
|
> span:not(.ivu-radio) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
.setting-template {
|
.setting-template {
|
||||||
> div {
|
> div {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user