Kaynağa Gözat

修改了创建任务弹窗的样式,未解决时间选择问题

追梦人 2 gün önce
ebeveyn
işleme
c3191b0d60

+ 103 - 47
src/app/shared/task-modal/task-modal.component.html

@@ -1,57 +1,113 @@
-<ion-header>
-  <ion-toolbar>
-    <ion-title>新建任务</ion-title>
+<ion-header class="ion-no-border">
+  <ion-toolbar color="light">
+    <ion-buttons slot="start">
+      <ion-button (click)="cancel()">
+        <ion-icon name="close" slot="icon-only"></ion-icon>
+      </ion-button>
+    </ion-buttons>
+    <ion-title class="ion-text-center">新建任务</ion-title>
     <ion-buttons slot="end">
-      <ion-button (click)="cancel()">取消</ion-button>
-      <ion-button (click)="confirm()" [strong]="true">确认</ion-button>
+      <ion-button (click)="confirm()" [strong]="true" color="primary">
+        保存
+      </ion-button>
     </ion-buttons>
   </ion-toolbar>
 </ion-header>
 
-<ion-content class="ion-padding">
-  <ion-item>
-    <ion-label position="stacked">任务名称</ion-label>
-    <ion-input [(ngModel)]="task.title" placeholder="输入任务名称"></ion-input>
-  </ion-item>
+<ion-content class="ion-padding-horizontal">
+  <ion-list lines="none">
+    <!-- 任务名称 -->
+    <ion-item fill="outline" class="ion-margin-vertical">
+      <ion-label position="stacked">任务名称</ion-label>
+      <ion-input
+        [(ngModel)]="task.title"
+        placeholder="请输入任务名称"
+        clearOnEdit
+      ></ion-input>
+    </ion-item>
 
-  <ion-item>
-    <ion-label position="stacked">任务标签</ion-label>
-    <ion-input [(ngModel)]="newTag" placeholder="输入标签并按回车" (keyup.enter)="addTag()"></ion-input>
-    <ion-buttons slot="end">
-      <ion-button (click)="addTag()">
+    <!-- 任务标签 -->
+    <ion-item fill="outline" class="ion-margin-vertical">
+      <ion-label position="stacked">任务标签</ion-label>
+      <ion-input
+        [(ngModel)]="newTag"
+        placeholder="输入标签后按回车"
+        (keyup.enter)="addTag()"
+      ></ion-input>
+      <ion-button
+        slot="end"
+        fill="clear"
+        (click)="addTag()"
+        [disabled]="!newTag"
+      >
         <ion-icon name="add" slot="icon-only"></ion-icon>
       </ion-button>
-    </ion-buttons>
-  </ion-item>
-
-  <div class="tags-container">
-    <ion-chip *ngFor="let tag of task.tags; let i = index" color="primary">
-      {{ tag }}
-      <ion-icon name="close" (click)="removeTag(i)"></ion-icon>
-    </ion-chip>
-  </div>
-
-  <ion-item>
-    <ion-label position="stacked">截止时间</ion-label>
-    <ion-datetime-button datetime="datetime"></ion-datetime-button>
-    <ion-modal [keepContentsMounted]="true">
-      <ion-datetime [(ngModel)]="task.dueDate" id="datetime"></ion-datetime>
-    </ion-modal>
-  </ion-item>
-
-  <ion-item>
-    <ion-label position="stacked">子任务</ion-label>
-    <ion-button fill="clear" slot="end" (click)="addSubtask()">
-      <ion-icon name="add" slot="icon-only"></ion-icon>
-    </ion-button>
-  </ion-item>
-
-  <div class="subtasks-container">
-    <ion-item *ngFor="let subtask of task.subtasks; let i = index">
-      <ion-input [(ngModel)]="task.subtasks[i]" placeholder="子任务内容"></ion-input>
-      <ion-button fill="clear" slot="end" (click)="removeSubtask(i)">
-        <ion-icon name="trash" color="danger"></ion-icon>
-      </ion-button>
     </ion-item>
-  </div>
+
+    <!-- 标签展示 -->
+    <div class="tags-container ion-margin-bottom">
+      <ion-chip
+        *ngFor="let tag of task.tags; let i = index"
+        color="medium"
+        outline
+      >
+        {{ tag }}
+        <ion-icon name="close" (click)="removeTag(i)"></ion-icon>
+      </ion-chip>
+    </div>
+
+    <!-- 截止时间 -->
+    <ion-item
+      fill="outline"
+      class="ion-margin-vertical"
+      button
+      detail="false"
+      (click)="openDateTimePicker()"
+    >
+      <ion-label>截止时间</ion-label>
+      <ion-text slot="end">{{ task.dueDate | date: 'MM月dd日 HH:mm' }}</ion-text>
+    </ion-item>
+
+    <!-- 日期选择器 -->
+
+
+    <!-- 子任务 -->
+    <div class="subtask-section ion-margin-vertical">
+      <ion-item lines="none">
+        <ion-label>子任务列表</ion-label>
+        <ion-button fill="clear" (click)="addSubtask()">
+          <ion-icon name="add-circle" slot="start"></ion-icon>
+          添加子任务
+        </ion-button>
+      </ion-item>
+
+      <ion-list class="subtask-list">
+        <ion-item *ngFor="let subtask of task.subtasks; let i = index">
+          <ion-input
+            [(ngModel)]="task.subtasks[i]"
+            placeholder="子任务描述"
+            clearOnEdit
+          ></ion-input>
+          <ion-button
+            fill="clear"
+            color="danger"
+            (click)="removeSubtask(i)"
+          >
+            <ion-icon name="trash" slot="icon-only"></ion-icon>
+          </ion-button>
+        </ion-item>
+      </ion-list>
+    </div>
+
+    <!-- 备注 -->
+    <ion-item fill="outline" class="ion-margin-vertical">
+      <ion-label position="stacked">任务备注</ion-label>
+      <ion-textarea
+        [(ngModel)]="task.note"
+        placeholder="请输入任务备注(可选)"
+        autoGrow
+        rows="3"
+      ></ion-textarea>
+    </ion-item>
+  </ion-list>
 </ion-content>

+ 70 - 10
src/app/shared/task-modal/task-modal.component.scss

@@ -1,25 +1,85 @@
+ion-header {
+  ion-toolbar {
+    --padding-start: 12px;
+    --padding-end: 12px;
+
+    ion-title {
+      font-weight: 500;
+      letter-spacing: 0.5px;
+    }
+  }
+}
+
+ion-content {
+  --padding-top: 16px;
+  --padding-bottom: 24px;
+}
+
 .tags-container {
   display: flex;
   gap: 8px;
   flex-wrap: wrap;
   margin: 12px 0;
+
+  ion-chip {
+    --background: var(--ion-color-light);
+    --color: var(--ion-color-medium);
+    transition: all 0.2s ease;
+
+    &:hover {
+      --background: var(--ion-color-light-shade);
+    }
+
+    ion-icon {
+      font-size: 16px;
+      margin-left: 6px;
+      cursor: pointer;
+    }
+  }
 }
 
-.subtasks-container {
+.subtask-section {
+  border-radius: 12px;
+  background: var(--ion-color-light);
+  padding: 8px 0;
+
   ion-item {
-    --padding-start: 0;
-    --inner-padding-end: 0;
-    margin-bottom: 8px;
+    --background: transparent;
+    --inner-padding-end: 8px;
+  }
+
+  .subtask-list {
+    background: white;
+    border-radius: 8px;
+    margin: 8px 16px;
+    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
 
-    ion-button {
-      margin-inline-end: -8px;
+    ion-item {
+      --min-height: 48px;
+      --padding-start: 16px;
+
+      ion-button {
+        --padding-start: 0;
+        --padding-end: 0;
+      }
     }
   }
 }
 
 ion-datetime {
-  --background: var(--ion-color-light);
-  --background-rgb: 255, 255, 255;
-  border-radius: 8px;
-  padding: 12px;
+  --background: white;
+  border-radius: 16px;
+  margin: 16px;
+  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
+
+  &::part(calendar-day):hover {
+    background: var(--ion-color-light);
+  }
+}
+
+ion-textarea {
+  --padding-top: 12px;
+  --padding-bottom: 12px;
+  font-size: 14px;
+  line-height: 1.4;
 }

+ 36 - 2
src/app/shared/task-modal/task-modal.component.ts

@@ -2,6 +2,7 @@ import { Component } from '@angular/core';
 import { IonicModule, ModalController } from '@ionic/angular';
 import { CommonModule } from '@angular/common';
 import { FormsModule } from '@angular/forms';
+import { IonDatetime } from '@ionic/angular';
 
 @Component({
   selector: 'app-task-modal',
@@ -11,20 +12,50 @@ import { FormsModule } from '@angular/forms';
   imports: [IonicModule, CommonModule, FormsModule]
 })
 export class TaskModalComponent {
+  // 日期范围配置
+  dateConfig = {
+    min: new Date().toISOString(),
+    max: new Date(new Date().setFullYear(new Date().getFullYear() + 1)).toISOString(),
+    buttons: {
+      doneText: '确定',
+      cancelText: '取消'
+    }
+  };
+
   task = {
     title: '',
     tags: [] as string[],
     dueDate: new Date().toISOString(),
-    subtasks: [''] as string[]
+    subtasks: [''] as string[],
+    note: ''  // 新增备注字段
   };
 
   newTag = '';
 
   constructor(private modalCtrl: ModalController) {}
 
+  // 新增模态控制器实现
+  async openDateTimePicker() {
+    const datetimeModal = await this.modalCtrl.create({
+      component: IonDatetime,
+      componentProps: {
+        presentation: 'date-time',
+        value: this.task.dueDate,
+        min: this.dateConfig.min,
+        max: this.dateConfig.max
+      }
+    });
+
+    datetimeModal.onDidDismiss().then(({ data }) => {
+      if (data) this.task.dueDate = data;
+    });
+
+    await datetimeModal.present();
+  }
+
   addTag() {
     if (this.newTag) {
-      this.task.tags.push(this.newTag);
+      this.task.tags.push(this.newTag.trim());
       this.newTag = '';
     }
   }
@@ -46,6 +77,9 @@ export class TaskModalComponent {
   }
 
   confirm() {
+    if (!this.task.title) {
+      return;
+    }
     this.modalCtrl.dismiss(this.task);
   }
 }