refactor: 任务中心合并任务分发(导航 9→8,任务卡进入分发明细)
This commit is contained in:
@@ -204,7 +204,6 @@ type NavKey =
|
||||
| "overview"
|
||||
| "projects"
|
||||
| "tasks"
|
||||
| "distributions"
|
||||
| "resources"
|
||||
| "partners"
|
||||
| "recovery"
|
||||
@@ -215,7 +214,6 @@ const NAV_ITEMS: Array<{ key: NavKey; label: string; mark: string }> = [
|
||||
{ key: "overview", label: "工作台", mark: "⌂" },
|
||||
{ key: "projects", label: "项目中心", mark: "▦" },
|
||||
{ key: "tasks", label: "任务中心", mark: "▤" },
|
||||
{ key: "distributions", label: "任务分发", mark: "↗" },
|
||||
{ key: "resources", label: "KOC资源", mark: "◎" },
|
||||
{ key: "partners", label: "合作方", mark: "Ⓒ" },
|
||||
{ key: "recovery", label: "数据回收", mark: "◫" },
|
||||
@@ -1036,12 +1034,8 @@ export default function Home({ currentUser }: { currentUser: AuthUser }) {
|
||||
subtitle: "按项目组织任务群与总群成员,一键把任务分发到项目各群。",
|
||||
},
|
||||
tasks: {
|
||||
title: "内容任务",
|
||||
subtitle: "从飞书同步内容,按数量开放给合作方领取。",
|
||||
},
|
||||
distributions: {
|
||||
title: "内容分发",
|
||||
subtitle: "先按任务查看进度,再进入单个任务处理每篇笔记。",
|
||||
title: "任务中心",
|
||||
subtitle: "从飞书同步内容、开放领取,并按任务跟进每篇笔记的分发进度。",
|
||||
},
|
||||
resources: {
|
||||
title: "KOC资源",
|
||||
@@ -1186,19 +1180,14 @@ export default function Home({ currentUser }: { currentUser: AuthUser }) {
|
||||
{activeNav === "tasks" && (
|
||||
<TasksPage
|
||||
tasks={data.tasks}
|
||||
distributions={data.distributions}
|
||||
portalUrl={data.portal_url}
|
||||
canRelease={isManager}
|
||||
working={working}
|
||||
onCreate={() => setTaskModalOpen(true)}
|
||||
onCopyShare={copyTaskShareLink}
|
||||
onPushToGroups={(task) => setGroupPushTask(task)}
|
||||
onOneClickPush={(task) => setOnePushTask(task)}
|
||||
/>
|
||||
)}
|
||||
{activeNav === "distributions" && (
|
||||
<DistributionPage
|
||||
tasks={data.tasks}
|
||||
distributions={data.distributions}
|
||||
canRelease={isManager}
|
||||
working={working}
|
||||
onRelease={async (distribution) =>
|
||||
runAction(
|
||||
{
|
||||
@@ -3945,7 +3934,7 @@ function OverviewPage({
|
||||
<h2>当前闭环</h2>
|
||||
<p>每篇内容只沿着一条记录向前走</p>
|
||||
</div>
|
||||
<button className="text-button" onClick={() => onNavigate("distributions")}>查看全部</button>
|
||||
<button className="text-button" onClick={() => onNavigate("tasks")}>查看全部</button>
|
||||
</div>
|
||||
<div className="workflow-track">
|
||||
<div className="workflow-step done">
|
||||
@@ -4016,7 +4005,7 @@ function OverviewPage({
|
||||
<section className="panel table-panel">
|
||||
<div className="panel-heading">
|
||||
<div><h2>最近分发</h2><p>领取、发布账号与回收状态一眼看清</p></div>
|
||||
<button className="text-button" onClick={() => onNavigate("distributions")}>查看全部</button>
|
||||
<button className="text-button" onClick={() => onNavigate("tasks")}>查看全部</button>
|
||||
</div>
|
||||
<DistributionTable distributions={distributions} compact />
|
||||
</section>
|
||||
@@ -4026,19 +4015,43 @@ function OverviewPage({
|
||||
|
||||
function TasksPage({
|
||||
tasks,
|
||||
distributions,
|
||||
portalUrl,
|
||||
canRelease,
|
||||
working,
|
||||
onCreate,
|
||||
onCopyShare,
|
||||
onPushToGroups,
|
||||
onOneClickPush,
|
||||
onRelease,
|
||||
}: {
|
||||
tasks: Task[];
|
||||
distributions: Distribution[];
|
||||
portalUrl: string;
|
||||
canRelease: boolean;
|
||||
working: boolean;
|
||||
onCreate: () => void;
|
||||
onCopyShare: (task: Task) => void;
|
||||
onPushToGroups: (task: Task) => void;
|
||||
onOneClickPush: (task: Task) => void;
|
||||
onRelease: (distribution: Distribution) => Promise<boolean>;
|
||||
}) {
|
||||
const [selectedTaskId, setSelectedTaskId] = useState<string | null>(null);
|
||||
const selectedTask = tasks.find((task) => task.id === selectedTaskId);
|
||||
|
||||
if (selectedTask) {
|
||||
return (
|
||||
<TaskDistributionDetail
|
||||
task={selectedTask}
|
||||
distributions={distributions}
|
||||
canRelease={canRelease}
|
||||
working={working}
|
||||
onRelease={onRelease}
|
||||
onBack={() => setSelectedTaskId(null)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="stack">
|
||||
<section className="task-hero">
|
||||
@@ -4078,6 +4091,12 @@ function TasksPage({
|
||||
<div className="task-date"><span>截止日期</span><strong>{formatDate(task.due_at)}</strong></div>
|
||||
<span className={`status-pill ${task.status}`}>{statusLabel(task.status)}</span>
|
||||
<div className="task-share-actions">
|
||||
<button
|
||||
className="share-link-button"
|
||||
onClick={() => setSelectedTaskId(task.id)}
|
||||
>
|
||||
分发明细
|
||||
</button>
|
||||
<button
|
||||
className="share-link-button"
|
||||
onClick={() => onCopyShare(task)}
|
||||
@@ -4122,12 +4141,10 @@ function TasksPage({
|
||||
function TaskScopeList({
|
||||
tasks,
|
||||
distributions,
|
||||
mode,
|
||||
onOpen,
|
||||
}: {
|
||||
tasks: Task[];
|
||||
distributions: Distribution[];
|
||||
mode: "distribution" | "recovery";
|
||||
onOpen: (taskId: string) => void;
|
||||
}) {
|
||||
return (
|
||||
@@ -4147,9 +4164,6 @@ function TaskScopeList({
|
||||
const creatorComplete = published.filter(
|
||||
(item) => hasCreatorMetrics(item),
|
||||
).length;
|
||||
const progress = task.quantity
|
||||
? Math.round((task.claimed_quantity / task.quantity) * 100)
|
||||
: 0;
|
||||
return (
|
||||
<article className="task-scope-card" key={task.id}>
|
||||
<div className="task-scope-head">
|
||||
@@ -4180,36 +4194,23 @@ function TaskScopeList({
|
||||
<strong>历史示例内容表</strong>
|
||||
)}
|
||||
</div>
|
||||
{mode === "distribution" ? (
|
||||
<>
|
||||
<div className="task-scope-metrics">
|
||||
<div><span>{isScreenshotTask ? "任务总量" : "内容总量"}</span><strong>{task.quantity}</strong></div>
|
||||
<div><span>已领取</span><strong>{task.claimed_quantity}</strong></div>
|
||||
<div><span>{isScreenshotTask ? "已提交" : "已发布"}</span><strong>{isScreenshotTask ? submitted.length : published.length}</strong></div>
|
||||
</div>
|
||||
<div className="progress task-scope-progress">
|
||||
<span style={{ width: `${progress}%` }} />
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<div className="task-scope-metrics">
|
||||
{isScreenshotTask ? (
|
||||
<>
|
||||
<div><span>已领取</span><strong>{taskDistributions.length}</strong></div>
|
||||
<div><span>已提交</span><strong>{submitted.length}</strong></div>
|
||||
<div><span>待提交</span><strong>{taskDistributions.length - submitted.length}</strong></div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<div><span>已发布</span><strong>{published.length}</strong></div>
|
||||
<div><span>公开数据</span><strong>{publicDataComplete}</strong></div>
|
||||
<div><span>创作者数据</span><strong>{creatorComplete}</strong></div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<div className="task-scope-metrics">
|
||||
{isScreenshotTask ? (
|
||||
<>
|
||||
<div><span>已领取</span><strong>{taskDistributions.length}</strong></div>
|
||||
<div><span>已提交</span><strong>{submitted.length}</strong></div>
|
||||
<div><span>待提交</span><strong>{taskDistributions.length - submitted.length}</strong></div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<div><span>已发布</span><strong>{published.length}</strong></div>
|
||||
<div><span>公开数据</span><strong>{publicDataComplete}</strong></div>
|
||||
<div><span>创作者数据</span><strong>{creatorComplete}</strong></div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<button className="task-scope-open" onClick={() => onOpen(task.id)}>
|
||||
<span>{mode === "distribution" ? "查看分发明细" : "进入回收队列"}</span>
|
||||
<span>进入回收队列</span>
|
||||
<b>→</b>
|
||||
</button>
|
||||
</article>
|
||||
@@ -4258,217 +4259,34 @@ function TaskDetailHeader({
|
||||
);
|
||||
}
|
||||
|
||||
function DistributionPage({
|
||||
tasks,
|
||||
function TaskDistributionDetail({
|
||||
task,
|
||||
distributions,
|
||||
canRelease,
|
||||
working,
|
||||
onRelease,
|
||||
onBack,
|
||||
}: {
|
||||
tasks: Task[];
|
||||
task: Task;
|
||||
distributions: Distribution[];
|
||||
canRelease: boolean;
|
||||
working: boolean;
|
||||
onRelease: (distribution: Distribution) => Promise<boolean>;
|
||||
onBack: () => void;
|
||||
}) {
|
||||
const [selectedTaskId, setSelectedTaskId] = useState<string | null>(null);
|
||||
const [taskQuery, setTaskQuery] = useState("");
|
||||
const [brandFilter, setBrandFilter] = useState("");
|
||||
const [contentTypeFilter, setContentTypeFilter] = useState("");
|
||||
const [platformFilter, setPlatformFilter] = useState("");
|
||||
const [openTaskFilter, setOpenTaskFilter] = useState<"brand" | "content" | "platform" | null>(null);
|
||||
const taskFiltersRef = useRef<HTMLDivElement | null>(null);
|
||||
const brandOptions = useMemo(
|
||||
() => Array.from(new Set(tasks.map((task) => task.brand).filter(Boolean))).sort((a, b) => a.localeCompare(b, "zh-CN")),
|
||||
[tasks],
|
||||
);
|
||||
const brandFilterOptions = useMemo(
|
||||
() => [{ value: "", label: "全部品牌/项目" }, ...brandOptions.map((brand) => ({ value: brand, label: brand }))],
|
||||
[brandOptions],
|
||||
);
|
||||
const contentTypeOptions = [
|
||||
{ value: "", label: "全部内容类型" },
|
||||
{ value: "图文", label: "图文" },
|
||||
{ value: "视频", label: "视频" },
|
||||
{ value: "截图回收", label: "截图回收" },
|
||||
];
|
||||
const platformOptions = [
|
||||
{ value: "", label: "全部平台" },
|
||||
{ value: "小红书", label: "小红书" },
|
||||
{ value: "抖音", label: "抖音" },
|
||||
];
|
||||
const taskFilterControls = [
|
||||
{ key: "brand" as const, label: "品牌/项目", value: brandFilter, options: brandFilterOptions },
|
||||
{ key: "content" as const, label: "内容类型", value: contentTypeFilter, options: contentTypeOptions },
|
||||
{ key: "platform" as const, label: "平台", value: platformFilter, options: platformOptions },
|
||||
];
|
||||
useEffect(() => {
|
||||
const closeOnOutsideClick = (event: MouseEvent) => {
|
||||
if (!taskFiltersRef.current?.contains(event.target as Node)) {
|
||||
setOpenTaskFilter(null);
|
||||
}
|
||||
};
|
||||
document.addEventListener("mousedown", closeOnOutsideClick);
|
||||
return () => document.removeEventListener("mousedown", closeOnOutsideClick);
|
||||
}, []);
|
||||
const setTaskFilterValue = (key: "brand" | "content" | "platform", value: string) => {
|
||||
if (key === "brand") setBrandFilter(value);
|
||||
if (key === "content") setContentTypeFilter(value);
|
||||
if (key === "platform") setPlatformFilter(value);
|
||||
};
|
||||
const selectTaskFilter = (key: "brand" | "content" | "platform", value: string) => {
|
||||
setTaskFilterValue(key, value);
|
||||
setOpenTaskFilter(null);
|
||||
};
|
||||
const filteredTasks = useMemo(() => {
|
||||
const query = taskQuery.trim().toLocaleLowerCase("zh-CN");
|
||||
const brandQuery = brandFilter.trim().toLocaleLowerCase("zh-CN");
|
||||
const contentTypeQuery = contentTypeFilter.trim().toLocaleLowerCase("zh-CN");
|
||||
const platformQuery = platformFilter.trim().toLocaleLowerCase("zh-CN");
|
||||
return tasks.filter((task) => {
|
||||
const taskContentType = task.task_type === "screenshot_collect"
|
||||
? "截图回收"
|
||||
: task.content_format === "video" ? "视频" : "图文";
|
||||
return (
|
||||
(!query || task.name.toLocaleLowerCase("zh-CN").includes(query)) &&
|
||||
(!brandQuery || task.brand.toLocaleLowerCase("zh-CN").includes(brandQuery)) &&
|
||||
(!contentTypeQuery || taskContentType.toLocaleLowerCase("zh-CN").includes(contentTypeQuery)) &&
|
||||
(!platformQuery || task.platform.toLocaleLowerCase("zh-CN").includes(platformQuery))
|
||||
);
|
||||
});
|
||||
}, [brandFilter, contentTypeFilter, platformFilter, taskQuery, tasks]);
|
||||
const hasTaskFilters = Boolean(
|
||||
taskQuery.trim() || brandFilter.trim() || contentTypeFilter.trim() || platformFilter.trim(),
|
||||
);
|
||||
const [releaseTarget, setReleaseTarget] = useState<Distribution | null>(null);
|
||||
const selectedTask = tasks.find((task) => task.id === selectedTaskId);
|
||||
if (!selectedTask) {
|
||||
return (
|
||||
<div className="stack">
|
||||
<div className="section-intro">
|
||||
<div><p className="eyebrow">按任务管理</p><h2>选择一个分发任务</h2></div>
|
||||
<p>每个任务独立查看领取、发布和账号识别进度,不混排不同项目的笔记。</p>
|
||||
</div>
|
||||
<section className="distribution-task-toolbar" aria-label="筛选分发任务">
|
||||
<label className="distribution-task-search">
|
||||
<span aria-hidden="true">⌕</span>
|
||||
<input
|
||||
type="search"
|
||||
value={taskQuery}
|
||||
onChange={(event) => setTaskQuery(event.target.value)}
|
||||
placeholder="搜索任务名称"
|
||||
aria-label="按任务名称模糊搜索"
|
||||
/>
|
||||
</label>
|
||||
<div className="distribution-task-filter-group" ref={taskFiltersRef}>
|
||||
{taskFilterControls.map((filter) => {
|
||||
const normalizedFilterValue = filter.value.trim().toLocaleLowerCase("zh-CN");
|
||||
const visibleOptions = filter.options.filter((option) => (
|
||||
!normalizedFilterValue ||
|
||||
option.label.toLocaleLowerCase("zh-CN").includes(normalizedFilterValue)
|
||||
));
|
||||
return (
|
||||
<div
|
||||
className={`distribution-task-filter-combobox ${filter.key === "brand" ? "brand" : ""}`}
|
||||
key={filter.key}
|
||||
>
|
||||
<div className="distribution-task-filter-input">
|
||||
<span aria-hidden="true">⌕</span>
|
||||
<input
|
||||
type="search"
|
||||
role="combobox"
|
||||
aria-autocomplete="list"
|
||||
aria-expanded={openTaskFilter === filter.key}
|
||||
aria-controls={`distribution-task-${filter.key}-menu`}
|
||||
value={filter.value}
|
||||
placeholder={`搜索${filter.label}`}
|
||||
aria-label={`模糊搜索${filter.label}`}
|
||||
onFocus={() => setOpenTaskFilter(filter.key)}
|
||||
onChange={(event) => {
|
||||
setTaskFilterValue(filter.key, event.target.value);
|
||||
setOpenTaskFilter(filter.key);
|
||||
}}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === "Escape") setOpenTaskFilter(null);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{openTaskFilter === filter.key ? (
|
||||
<div
|
||||
id={`distribution-task-${filter.key}-menu`}
|
||||
className="distribution-task-filter-menu"
|
||||
role="listbox"
|
||||
aria-label={`选择${filter.label}`}
|
||||
>
|
||||
<div className="distribution-task-filter-menu-options">
|
||||
{visibleOptions.map((option) => (
|
||||
<button
|
||||
key={option.value}
|
||||
type="button"
|
||||
role="option"
|
||||
aria-selected={filter.value === option.value}
|
||||
className={filter.value === option.value ? "selected" : ""}
|
||||
onClick={() => selectTaskFilter(filter.key, option.value)}
|
||||
>
|
||||
<span>{option.label}</span>
|
||||
{filter.value === option.value ? <small>✓</small> : null}
|
||||
</button>
|
||||
))}
|
||||
{visibleOptions.length === 0 ? (
|
||||
<span className="distribution-task-filter-empty">没有匹配项</span>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
className="distribution-task-clear"
|
||||
disabled={!hasTaskFilters}
|
||||
onClick={() => {
|
||||
setTaskQuery("");
|
||||
setBrandFilter("");
|
||||
setContentTypeFilter("");
|
||||
setPlatformFilter("");
|
||||
setOpenTaskFilter(null);
|
||||
}}
|
||||
>
|
||||
清空筛选
|
||||
</button>
|
||||
<span className="distribution-task-count">共 <b>{filteredTasks.length}</b> 个任务</span>
|
||||
</section>
|
||||
{filteredTasks.length > 0 ? (
|
||||
<TaskScopeList
|
||||
tasks={filteredTasks}
|
||||
distributions={distributions}
|
||||
mode="distribution"
|
||||
onOpen={setSelectedTaskId}
|
||||
/>
|
||||
) : (
|
||||
<section className="distribution-task-empty">
|
||||
<strong>没有符合条件的任务</strong>
|
||||
<span>可以调整任务名称或清空筛选条件</span>
|
||||
</section>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const taskDistributions = distributions.filter(
|
||||
(item) => item.task_id === selectedTask.id,
|
||||
(item) => item.task_id === task.id,
|
||||
);
|
||||
const isScreenshotTask = selectedTask.task_type === "screenshot_collect";
|
||||
const isScreenshotTask = task.task_type === "screenshot_collect";
|
||||
const published = taskDistributions.filter((item) => item.publish_url).length;
|
||||
const submitted = taskDistributions.filter((item) => item.result_submitted_at).length;
|
||||
return (
|
||||
<div className="stack">
|
||||
<TaskDetailHeader
|
||||
task={selectedTask}
|
||||
task={task}
|
||||
label={isScreenshotTask ? "截图任务分发" : "内容分发"}
|
||||
onBack={() => setSelectedTaskId(null)}
|
||||
onBack={onBack}
|
||||
/>
|
||||
<div className="inline-summary">
|
||||
<div><span>已领取</span><strong>{taskDistributions.length}</strong></div>
|
||||
@@ -4476,7 +4294,7 @@ function DistributionPage({
|
||||
<div><span>{isScreenshotTask ? "已提交截图" : "已回填链接"}</span><strong>{isScreenshotTask ? submitted : published}</strong></div>
|
||||
<i />
|
||||
<div><span>{isScreenshotTask ? "待提交" : "待发布"}</span><strong>{taskDistributions.length - (isScreenshotTask ? submitted : published)}</strong></div>
|
||||
<div className="summary-note"><span className="pulse-dot" />当前仅展示“{selectedTask.name}”</div>
|
||||
<div className="summary-note"><span className="pulse-dot" />当前仅展示“{task.name}”</div>
|
||||
</div>
|
||||
<section className="panel table-panel">
|
||||
<div className="panel-heading">
|
||||
@@ -5933,7 +5751,6 @@ function RecoveryPage({
|
||||
<TaskScopeList
|
||||
tasks={tasks}
|
||||
distributions={distributions}
|
||||
mode="recovery"
|
||||
onOpen={setSelectedTaskId}
|
||||
/>
|
||||
</div>
|
||||
|
||||
262
app/globals.css
262
app/globals.css
@@ -2052,230 +2052,6 @@ a {
|
||||
background: #eef7f9;
|
||||
}
|
||||
|
||||
.distribution-task-toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 9px;
|
||||
padding: 13px;
|
||||
border: 1px solid #e5ebe8;
|
||||
border-radius: 12px;
|
||||
background: #f8faf8;
|
||||
}
|
||||
|
||||
.distribution-task-search {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
min-width: 240px;
|
||||
height: 38px;
|
||||
flex: 1 1 320px;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin: 0;
|
||||
padding: 0 12px;
|
||||
border: 1px solid #dfe6e2;
|
||||
border-radius: 9px;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.distribution-task-search:focus-within {
|
||||
border-color: #74b79f;
|
||||
box-shadow: 0 0 0 3px rgb(31 143 107 / 0.08);
|
||||
}
|
||||
|
||||
.distribution-task-search > span {
|
||||
display: grid;
|
||||
width: 18px;
|
||||
flex: 0 0 18px;
|
||||
place-items: center;
|
||||
color: #83918c;
|
||||
font-size: 15px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.distribution-task-search input {
|
||||
min-width: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
outline: 0;
|
||||
background: transparent;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.distribution-task-filter-group {
|
||||
display: flex;
|
||||
flex: 0 1 auto;
|
||||
align-items: center;
|
||||
gap: 9px;
|
||||
}
|
||||
|
||||
.distribution-task-filter-combobox {
|
||||
position: relative;
|
||||
width: 150px;
|
||||
flex: 0 1 150px;
|
||||
}
|
||||
|
||||
.distribution-task-filter-combobox.brand {
|
||||
width: 176px;
|
||||
flex-basis: 176px;
|
||||
}
|
||||
|
||||
.distribution-task-filter-input {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 38px;
|
||||
flex: none;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
gap: 10px;
|
||||
padding: 0 11px;
|
||||
border: 1px solid #dfe6e2;
|
||||
border-radius: 9px;
|
||||
outline: 0;
|
||||
color: #28332f;
|
||||
background: white;
|
||||
font-size: 9px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.distribution-task-filter-input > span {
|
||||
display: grid;
|
||||
width: 16px;
|
||||
flex: 0 0 16px;
|
||||
place-items: center;
|
||||
color: #83918c;
|
||||
font-size: 13px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.distribution-task-filter-input input {
|
||||
display: block;
|
||||
min-width: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
flex: 1 1 auto;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
outline: 0;
|
||||
color: #28332f;
|
||||
background: transparent;
|
||||
font-size: 9px;
|
||||
}
|
||||
|
||||
.distribution-task-filter-input:hover,
|
||||
.distribution-task-filter-input:focus-within {
|
||||
border-color: #74b79f;
|
||||
box-shadow: 0 0 0 3px rgb(31 143 107 / 0.08);
|
||||
}
|
||||
|
||||
.distribution-task-filter-menu {
|
||||
position: absolute;
|
||||
z-index: 60;
|
||||
top: calc(100% + 7px);
|
||||
left: 0;
|
||||
display: grid;
|
||||
width: max(100%, 230px);
|
||||
padding: 8px;
|
||||
border: 1px solid #dce8e3;
|
||||
border-radius: 12px;
|
||||
background: white;
|
||||
box-shadow: 0 16px 36px rgb(20 45 37 / 0.16);
|
||||
}
|
||||
|
||||
.distribution-task-filter-menu-options {
|
||||
display: grid;
|
||||
max-height: 240px;
|
||||
gap: 3px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.distribution-task-filter-menu-options button {
|
||||
display: flex;
|
||||
min-height: 34px;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 10px;
|
||||
padding: 0 10px;
|
||||
border: 0;
|
||||
border-radius: 8px;
|
||||
color: #34423d;
|
||||
background: transparent;
|
||||
font-size: 9px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.distribution-task-filter-menu-options button:hover,
|
||||
.distribution-task-filter-menu-options button:focus-visible {
|
||||
outline: 0;
|
||||
background: #f3f9f6;
|
||||
}
|
||||
|
||||
.distribution-task-filter-menu-options button.selected {
|
||||
color: var(--green-deep);
|
||||
background: #eaf6f1;
|
||||
font-weight: 650;
|
||||
}
|
||||
|
||||
.distribution-task-filter-menu-options button small {
|
||||
color: #6f9d8d;
|
||||
font-size: 8px;
|
||||
}
|
||||
|
||||
.distribution-task-filter-empty {
|
||||
padding: 12px 10px;
|
||||
color: #98a39f;
|
||||
font-size: 9px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.distribution-task-clear {
|
||||
height: 38px;
|
||||
padding: 0 6px;
|
||||
border: 0;
|
||||
color: var(--green-deep);
|
||||
background: transparent;
|
||||
font-size: 9px;
|
||||
font-weight: 650;
|
||||
}
|
||||
|
||||
.distribution-task-count {
|
||||
margin-left: auto;
|
||||
color: #8c9894;
|
||||
font-size: 9px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.distribution-task-count b {
|
||||
color: var(--ink);
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.distribution-task-empty {
|
||||
display: grid;
|
||||
min-height: 190px;
|
||||
place-content: center;
|
||||
gap: 7px;
|
||||
border: 1px dashed #dce5e1;
|
||||
border-radius: 15px;
|
||||
color: #8d9894;
|
||||
background: #fbfcfb;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.distribution-task-empty strong {
|
||||
color: var(--ink);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.distribution-task-empty span {
|
||||
font-size: 9px;
|
||||
}
|
||||
|
||||
.task-source-line {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -2331,10 +2107,6 @@ a {
|
||||
letter-spacing: -0.03em;
|
||||
}
|
||||
|
||||
.task-scope-progress {
|
||||
margin-top: 13px;
|
||||
}
|
||||
|
||||
.task-scope-open {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
@@ -4952,11 +4724,6 @@ label small {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.distribution-task-count {
|
||||
width: 100%;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.workflow-track {
|
||||
overflow-x: auto;
|
||||
}
|
||||
@@ -5142,35 +4909,6 @@ label small {
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.distribution-task-toolbar {
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.distribution-task-search,
|
||||
.distribution-task-filter-group,
|
||||
.distribution-task-filter-combobox,
|
||||
.distribution-task-filter-combobox.brand {
|
||||
width: 100%;
|
||||
flex-basis: 100%;
|
||||
}
|
||||
|
||||
.distribution-task-filter-group {
|
||||
grid-template-columns: 1fr;
|
||||
display: grid;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.distribution-task-clear {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.distribution-task-count {
|
||||
display: flex;
|
||||
width: auto;
|
||||
align-items: center;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.resource-search,
|
||||
.resource-filter-search {
|
||||
width: 100%;
|
||||
|
||||
Reference in New Issue
Block a user