| @@ -12,6 +12,7 @@ export interface PrinterInputs { | |||
| name?: string; | |||
| code?: string; | |||
| type?: string; | |||
| brand?: string; | |||
| description?: string; | |||
| ip?: string; | |||
| port?: number; | |||
| @@ -10,6 +10,7 @@ export interface PrinterCombo { | |||
| code?: string; | |||
| name?: string; | |||
| type?: string; | |||
| brand?: string; | |||
| description?: string; | |||
| ip?: string; | |||
| port?: number; | |||
| @@ -21,6 +22,7 @@ export interface PrinterResult { | |||
| name?: string; | |||
| code?: string; | |||
| type?: string; | |||
| brand?: string; | |||
| description?: string; | |||
| ip?: string; | |||
| port?: number; | |||
| @@ -30,6 +30,7 @@ const CreatePrinter: React.FC = () => { | |||
| ip: "", | |||
| port: undefined, | |||
| type: "A4", | |||
| brand: "Canon", | |||
| dpi: undefined, | |||
| description: "", | |||
| }); | |||
| @@ -50,6 +51,18 @@ const CreatePrinter: React.FC = () => { | |||
| if (formData.type !== "Label") { | |||
| setFormData((prev) => ({ ...prev, dpi: undefined })); | |||
| } | |||
| if (formData.type === "A4") { | |||
| // A4: allow Canon/Brother (keep whatever is selected, default Canon from initial state) | |||
| if (!formData.brand) { | |||
| setFormData((prev) => ({ ...prev, brand: "Canon" })); | |||
| } | |||
| } else if (formData.type === "Label") { | |||
| // Label: preview Zebra | |||
| setFormData((prev) => ({ ...prev, brand: "Zebra" })); | |||
| } else { | |||
| // Other types (if any): no brand | |||
| setFormData((prev) => ({ ...prev, brand: undefined })); | |||
| } | |||
| }, [formData.type]); | |||
| const handleChange = useCallback((field: keyof PrinterInputs) => { | |||
| @@ -74,6 +87,13 @@ const CreatePrinter: React.FC = () => { | |||
| })); | |||
| }, []); | |||
| const handleBrandChange = useCallback((e: SelectChangeEvent) => { | |||
| setFormData((prev) => ({ | |||
| ...prev, | |||
| brand: e.target.value, | |||
| })); | |||
| }, []); | |||
| const handleDescriptionChange = useCallback((_e: any, newValue: string | null) => { | |||
| setFormData((prev) => ({ | |||
| ...prev, | |||
| @@ -155,6 +175,32 @@ const CreatePrinter: React.FC = () => { | |||
| </Select> | |||
| </FormControl> | |||
| </Grid> | |||
| {formData.type === "A4" && ( | |||
| <Grid item xs={12} md={6}> | |||
| <FormControl fullWidth> | |||
| <InputLabel>{t("Brand")}</InputLabel> | |||
| <Select | |||
| label={t("Brand")} | |||
| value={formData.brand ?? "Canon"} | |||
| onChange={handleBrandChange} | |||
| > | |||
| <MenuItem value="Canon">Canon</MenuItem> | |||
| <MenuItem value="Brother">Brother</MenuItem> | |||
| </Select> | |||
| </FormControl> | |||
| </Grid> | |||
| )} | |||
| {formData.type === "Label" && ( | |||
| <Grid item xs={12} md={6}> | |||
| <TextField | |||
| fullWidth | |||
| label={t("Brand")} | |||
| value={formData.brand ?? "Zebra"} | |||
| disabled | |||
| /> | |||
| </Grid> | |||
| )} | |||
| <Grid item xs={12} md={6}> | |||
| <TextField | |||
| fullWidth | |||
| @@ -16,7 +16,6 @@ import { | |||
| SelectChangeEvent, | |||
| Stack, | |||
| TextField, | |||
| Typography, | |||
| } from "@mui/material"; | |||
| import { Check, ArrowBack } from "@mui/icons-material"; | |||
| import { successDialog } from "../Swal/CustomAlerts"; | |||
| @@ -34,13 +33,24 @@ const EditPrinter: React.FC<Props> = ({ printer }) => { | |||
| ip: printer.ip || "", | |||
| port: printer.port || undefined, | |||
| type: printer.type || "", | |||
| brand: printer.brand ?? "Canon", | |||
| dpi: printer.dpi || undefined, | |||
| description: printer.description || "", | |||
| }); | |||
| useEffect(() => { | |||
| if (formData.type !== "Label") { | |||
| setFormData((prev) => ({ ...prev, dpi: undefined })); | |||
| } | |||
| if (formData.type === "A4") { | |||
| if (!formData.brand) { | |||
| setFormData((prev) => ({ ...prev, brand: "Canon" })); | |||
| } | |||
| } else if (formData.type === "Label") { | |||
| setFormData((prev) => ({ ...prev, brand: "Zebra" })); | |||
| } else { | |||
| setFormData((prev) => ({ ...prev, brand: undefined })); | |||
| } | |||
| }, [formData.type]); | |||
| const handleChange = useCallback((field: keyof PrinterInputs) => { | |||
| @@ -63,6 +73,14 @@ const EditPrinter: React.FC<Props> = ({ printer }) => { | |||
| })); | |||
| }, []); | |||
| const handleBrandChange = useCallback((e: SelectChangeEvent) => { | |||
| const value = e.target.value; | |||
| setFormData((prev) => ({ | |||
| ...prev, | |||
| brand: value, | |||
| })); | |||
| }, []); | |||
| const handleSubmit = useCallback(async () => { | |||
| setIsSubmitting(true); | |||
| try { | |||
| @@ -123,6 +141,31 @@ const EditPrinter: React.FC<Props> = ({ printer }) => { | |||
| </Select> | |||
| </FormControl> | |||
| </Grid> | |||
| {formData.type === "A4" && ( | |||
| <Grid item xs={12} md={6}> | |||
| <FormControl fullWidth> | |||
| <InputLabel>{t("Brand")}</InputLabel> | |||
| <Select | |||
| label={t("Brand")} | |||
| value={formData.brand ?? "Canon"} | |||
| onChange={handleBrandChange} | |||
| > | |||
| <MenuItem value="Canon">Canon</MenuItem> | |||
| <MenuItem value="Brother">Brother</MenuItem> | |||
| </Select> | |||
| </FormControl> | |||
| </Grid> | |||
| )} | |||
| {formData.type === "Label" && ( | |||
| <Grid item xs={12} md={6}> | |||
| <TextField | |||
| fullWidth | |||
| label={t("Brand")} | |||
| value={formData.brand ?? "Zebra"} | |||
| disabled | |||
| /> | |||
| </Grid> | |||
| )} | |||
| <Grid item xs={12} md={6}> | |||
| <TextField | |||
| fullWidth | |||
| @@ -134,6 +177,15 @@ const EditPrinter: React.FC<Props> = ({ printer }) => { | |||
| disabled={formData.type !== "Label"} | |||
| /> | |||
| </Grid> | |||
| <Grid item xs={12} md={6}> | |||
| <TextField | |||
| fullWidth | |||
| label={t("Description")} | |||
| value={formData.description || ""} | |||
| onChange={handleChange("description")} | |||
| variant="outlined" | |||
| /> | |||
| </Grid> | |||
| <Grid item xs={12}> | |||
| <Stack direction="row" spacing={2}> | |||
| <Button | |||
| @@ -51,6 +51,10 @@ const PrinterSearch: React.FC<Props> = ({ printers }) => { | |||
| paramName: "type", | |||
| type: "text", | |||
| }, | |||
| { | |||
| label: t("Brand"), | |||
| paramName: "brand", | |||
| type: "text" }, | |||
| ], | |||
| [t], | |||
| ); | |||
| @@ -129,6 +133,13 @@ const PrinterSearch: React.FC<Props> = ({ printers }) => { | |||
| align: "left", | |||
| headerAlign: "left", | |||
| sx: { width: "15%", minWidth: "100px" }, | |||
| }, | |||
| { | |||
| name: "brand", | |||
| label: t("Brand"), | |||
| align: "left", | |||
| headerAlign: "left", | |||
| sx: { width: "12%", minWidth: "90px" }, | |||
| }, | |||
| { | |||
| name: "dpi", | |||
| @@ -182,6 +193,11 @@ const PrinterSearch: React.FC<Props> = ({ printers }) => { | |||
| printer.type?.toLowerCase().includes(query.type?.toLowerCase() || "") | |||
| ); | |||
| } | |||
| if (query.brand && query.brand.trim()) { | |||
| results = results.filter((printer) => | |||
| printer.brand?.toLowerCase().includes(query.brand?.toLowerCase() || "") | |||
| ); | |||
| } | |||
| setFilteredPrinters(results); | |||
| setPagingController({ pageNum: 1, pageSize: pagingController.pageSize }); | |||
| @@ -526,5 +526,6 @@ | |||
| "Auto-refresh every 5 minutes": "每5分鐘自動刷新", | |||
| "Auto-refresh every 10 minutes": "每10分鐘自動刷新", | |||
| "Auto-refresh every 15 minutes": "每15分鐘自動刷新", | |||
| "Auto-refresh every 1 minute": "每1分鐘自動刷新" | |||
| "Auto-refresh every 1 minute": "每1分鐘自動刷新", | |||
| "Brand": "品牌" | |||
| } | |||