kllay 16 stundas atpakaļ
vecāks
revīzija
827578b939

+ 2 - 0
src/settings.ts

@@ -115,6 +115,7 @@ export default {
             defaultType: "form",
             form: {
                 action: `/api/system/file/`,
+                // action: `/api/system/device/upload-image/`,
                 name: "file",
                 withCredentials: false,
                 uploadRequest: async ({ action, file, onProgress }: { action: string; file: any; onProgress: Function }) => {
@@ -138,6 +139,7 @@ export default {
                     // 上传完成后的结果处理, 此处应返回格式为{url:xxx,key:xxx}
                     return {
                         url: getBaseURL(ret.data.url),
+                        // url: getBaseURL(ret.data.image_url),
                         key: ret.data.id,
                         ...ret.data
                     };

+ 1 - 1
src/views/system/borrow/approval/api.ts

@@ -58,7 +58,7 @@ export function Switchspost(tenant_id:number) {
 
 export function BorrowingReview(id:number,action:string,remark:string) {
 	return request({
-		url: `/api/system/borrow/${id}/review/`,
+		url: `/api/system/borrow/application/${id}/review/`,
 		method: 'post',
 		data: {action,remark},
 	});

+ 1 - 1
src/views/system/borrow/component/BorrowTypeSelect/index.vue

@@ -31,7 +31,7 @@ watch(
 );
 
 const types = [
-	{ value: 0, label: '常规借用' },
+	// { value: 0, label: '常规借用' },
 	{ value: 1, label: '课堂借用' },
 	{ value: 2, label: '特殊借用' },
 ];

+ 5 - 5
src/views/system/borrow/component/SpecialBorrow/SelectDeviceDialog/index.vue

@@ -60,14 +60,14 @@ function fetchWarehouseMap() {
 
 async function fetchData(resetPage = false) {
 	if (resetPage) page.value = 1;
-	await fetchWarehouseMap(); // 先获取仓库映射表
+	await fetchWarehouseMap(); 
 	deviceApi.GetList({ page: page.value, limit: pageSize.value, category_name: search.value })
 	.then((res) => {
-		// tableData.value = res.data;
-		// 替换 warehouse 字段为名称
-		const devices = res.data.map((device) => ({
+		const devices = res.data
+		.filter(device => device.available_quantity > 0)
+		.map((device) => ({
             ...device,
-            warehouse: warehouseMap.value[device.warehouse] || `ID:${device.warehouse}`
+            warehouse: `${warehouseMap.value[device.warehouse] || `ID:${device.warehouse}`} (${device.available_quantity})`
         }));
 		tableData.value = devices;
 		// tableData.value = [...res.data];

+ 0 - 173
src/views/system/borrow/component/SpecialBorrow/index-back.vue

@@ -1,173 +0,0 @@
-<template>
-	<el-dialog v-model="visible" title="特殊借用申请单" width="75%" :close-on-click-modal="false" @close="onCancel">
-		<el-form :model="form" label-width="110px" label-position="top" :rules="rules" ref="formRef">
-			<el-row :gutter="16">
-				<el-col :span="8">
-					<el-form-item label="借用单编号" prop="application_no">
-						<el-input v-model="form.application_no" placeholder="自动生成" disabled />
-					</el-form-item>
-				</el-col>
-				<el-col :span="8">
-					<el-form-item label="借用人" prop="borrower_name">
-						<el-input v-model="form.borrower_name" placeholder="请输入借用人" disabled />
-					</el-form-item>
-				</el-col>
-				<el-col :span="8">
-					<el-form-item label="学号/工号" prop="user_code">
-						<el-input v-model="form.user_code" placeholder="请输入学号/工号" disabled />
-					</el-form-item>
-				</el-col>
-				<el-col :span="8">
-					<el-form-item label="联系电话" prop="emergency_phone">
-						<el-input v-model="form.emergency_phone" placeholder="请输入联系电话" disabled />
-					</el-form-item>
-				</el-col>
-				<el-col :span="8">
-					<el-form-item label="借用部门" prop="borrower_dept">
-						<el-input v-model="form.borrower_dept" placeholder="请输入借用部门" disabled />
-					</el-form-item>
-				</el-col>
-				<el-col :span="8">
-					<el-form-item label="预计归还时间" prop="expected_end_time">
-						<el-date-picker v-model="form.expected_end_time" type="datetime" placeholder="请选择预计归还时间" style="width: 100%" />
-					</el-form-item>
-				</el-col>
-				<el-col :span="4">
-					<el-form-item label="个人/团队" prop="team_type">
-						<el-select v-model="form.team_type" placeholder="请选择">
-							<el-option label="个人" :value="0" />
-							<el-option label="团队" :value="1" />
-						</el-select>
-					</el-form-item>
-				</el-col>
-				<el-col :span="4">
-					<el-form-item label="团队人数" prop="team_members_count">
-						<el-input v-model="form.team_members_count" placeholder="请输入" />
-					</el-form-item>
-				</el-col>
-				<el-col :span="16">
-					<el-form-item label="团队其他人员名单" prop="team_members">
-						<el-input v-model="form.team_members" placeholder="请输入团队其他人员名单" />
-					</el-form-item>
-				</el-col>
-				<el-col :span="24">
-					<el-form-item label="借用原因" prop="purpose">
-						<el-input v-model="form.purpose" type="textarea" placeholder="请输入借用原因" />
-					</el-form-item>
-				</el-col>
-				<el-col :span="24">
-					<el-form-item label="备注" prop="applicant_remark">
-						<el-input v-model="form.applicant_remark" type="textarea" placeholder="请输入备注" />
-					</el-form-item>
-				</el-col>
-			</el-row>
-			<div style="margin: 16px 0 8px 0; font-weight: bold">借用列表</div>
-			<el-table :data="form.items" border style="width: 100%; margin-bottom: 12px">
-				<el-table-column type="index" label="序号" width="60" />
-				<el-table-column prop="device_name" label="设备分类" />
-				<el-table-column prop="quantity" label="借用数量">
-					<template #default="{ row }">
-						<el-input v-model="row.quantity" placeholder="请输入" />
-					</template>
-				</el-table-column>
-				<el-table-column prop="location" label="存放仓库" />
-				<el-table-column label="操作" width="80">
-					<template #default="{ row, $index }">
-						<el-button type="text" style="color: red" @click="removeItem($index)">移除</el-button>
-					</template>
-				</el-table-column>
-			</el-table>
-			<el-button type="primary" @click="addItem">添加设备</el-button>
-			<div style="margin: 16px 0 8px 0; font-weight: bold">配件信息</div>
-			<el-input v-model="form.accessory_info" placeholder="请输入配件信息" />
-			<div style="margin: 16px 0 8px 0; font-weight: bold">附件</div>
-			<el-upload action="#" list-type="text">
-				<el-button type="primary">点击或拖拽上传</el-button>
-			</el-upload>
-		</el-form>
-		<template #footer>
-			<el-button @click="onCancel">关闭</el-button>
-			<el-button type="primary" @click="onSubmit">提交</el-button>
-		</template>
-		<SelectDeviceDialog v-model:visible="showSelectDeviceDialog" @confirm="onDeviceSelected" />
-	</el-dialog>
-</template>
-
-<script setup lang="ts">
-import { ref, watch, defineProps, defineEmits, onMounted } from 'vue';
-import SelectDeviceDialog from '../CommonBorrow/SelectDeviceDialog/index.vue';
-const props = defineProps<{ visible: boolean; modelValue?: any }>();
-const emit = defineEmits(['update:visible', 'update:modelValue', 'submit']);
-const visible = ref(props.visible);
-const formRef = ref();
-
-const form = ref({
-	application_no: '',
-	borrower_name: '',
-	emergency_phone: '',
-	user_code: '',
-	borrower_dept: '',
-	expected_end_time: '',
-	team_type: 0,
-	team_members_count: '',
-	team_members: '',
-	purpose: '',
-	applicant_remark: '',
-	items: [],
-	accessory_info: '',
-});
-const showSelectDeviceDialog = ref(false);
-
-// 自动填充用户信息
-onMounted(() => {
-	try {
-		const userInfo = JSON.parse(sessionStorage.getItem('userInfo') || '{}');
-		if (userInfo) {
-			form.value.borrower_name = userInfo.username || '';
-			form.value.user_code = userInfo.dept_info?.dept_id || '';
-			form.value.emergency_phone = userInfo.mobile || '';
-			form.value.borrower_dept = userInfo.dept_info?.dept_name || '';
-		}
-	} catch (e) {}
-});
-
-watch(
-	() => props.visible,
-	(v) => (visible.value = v)
-);
-watch(
-	() => props.modelValue,
-	(v) => {
-		if (v) Object.assign(form.value, v);
-	}
-);
-
-function addItem() {
-	showSelectDeviceDialog.value = true;
-}
-function onDeviceSelected(devices) {
-	form.value.items.push(
-		...devices.map((d) => ({
-			device: d.id,
-			device_name: d.name,
-			quantity: 1,
-			location: d.location,
-		}))
-	);
-}
-function removeItem(index) {
-	form.value.items.splice(index, 1);
-}
-function onCancel() {
-	emit('update:visible', false);
-}
-function onSubmit() {
-	formRef.value.validate((valid) => {
-		if (valid) {
-			emit('submit', { ...form.value });
-			emit('update:visible', false);
-		}
-	});
-}
-const rules = {};
-</script>

+ 39 - 16
src/views/system/borrow/component/SpecialBorrow/index.vue

@@ -1,14 +1,5 @@
 <template>
 	<el-dialog v-model="visible" title="特殊借用" width="75%" :close-on-click-modal="false" @close="onCancel">
-		<!-- <div style="margin-bottom: 16px">
-			<ol style="padding: 10px 30px; margin-bottom: 20px; border: 1px solid #409eff; border-radius: 5px; background: #e6f7ff">
-				<h2>借用须知:</h2>
-				<li>1、申请借用设备时必须本人来办理,借用期间设备由借用人负责保管。禁止转借他人</li>
-				<li>2、如因人为操作不当造成的设备损坏或设备损失,应由借用人按规定赔偿。</li>
-				<li>3、设备需按时归还,如逾期归还,将限制借用资格。</li>
-				<li>4、设备借用一周以内由实验室管理办公室审核,设备借用一周以上或非我院师生借用时还需实验中心领导审核。</li>
-			</ol>
-		</div> -->
 		<el-form :model="form" label-width="110px" label-position="top" :rules="rules" ref="formRef">
 			<el-row :gutter="16">
 				<el-col :span="8">
@@ -18,22 +9,22 @@
 				</el-col>
 				<el-col :span="8">
 					<el-form-item label="借用人" prop="emergency_contact">
-						<el-input v-model="form.emergency_contact" placeholder="请输入借用人" disabled />
+						<el-input v-model="form.emergency_contact" placeholder="请输入借用人"  />
 					</el-form-item>
 				</el-col>
 				<el-col :span="8">
 					<el-form-item label="学号/工号" prop="app_user_borrower">
-						<el-input v-model="form.app_user_borrower" placeholder="请输入学号/工号" disabled />
+						<el-input v-model="form.app_user_borrower" placeholder="请输入学号/工号"  />
 					</el-form-item>
 				</el-col>
 				<el-col :span="8">
 					<el-form-item label="联系电话" prop="emergency_phone">
-						<el-input v-model="form.emergency_phone" placeholder="请输入联系电话" disabled />
+						<el-input v-model="form.emergency_phone" placeholder="请输入联系电话"  />
 					</el-form-item>
 				</el-col>
 				<el-col :span="8">
 					<el-form-item label="借用部门" prop="borrower_dept">
-						<el-input v-model="form.borrower_dept" placeholder="请输入借用部门" disabled />
+						<el-input v-model="form.borrower_dept" placeholder="请输入借用部门"  />
 					</el-form-item>
 				</el-col>
 				<el-col :span="8">
@@ -49,12 +40,12 @@
 						</el-select>
 					</el-form-item>
 				</el-col>
-				<el-col :span="4" v-if="form.team_type===1">
+				<el-col :span="4" v-show="form.team_type===1">
 					<el-form-item label="团队人数" prop="team_members_count">
 						<el-input v-model="form.team_members_count" placeholder="请输入" />
 					</el-form-item>
 				</el-col>
-				<el-col :span="16" v-if="form.team_type===1">
+				<el-col :span="16" v-show="form.team_type===1">
 					<el-form-item label="团队其他人员名单" prop="team_members">
 						<el-input v-model="form.team_members" placeholder="请输入团队其他人员名单" />
 					</el-form-item>
@@ -141,6 +132,38 @@ const form = ref({
 });
 const showSelectDeviceDialog = ref(false);
 
+
+const rules = {
+  emergency_contact: [
+    { required: true, message: '请输入借用人', trigger: 'change' },
+  ],
+  app_user_borrower: [
+    { required: true, message: '请输入学号或工号', trigger: 'change' },
+  ],
+  emergency_phone: [
+    { required: true, message: '请输入联系电话', trigger: 'change' },
+  ],
+  borrower_dept: [
+    { required: true, message: '请输入借用部门', trigger: 'change' },
+  ],
+  expected_end_time: [
+    { required: true, message: '请输选择归还时间', trigger: 'change' },
+  ],
+  team_type: [
+    { required: true, message: '请选择个人或者团队', trigger: 'change' },
+  ],
+  purpose: [
+    { required: true, message: '请输入借用原因', trigger: 'change' },
+  ],
+  applicant_remark_type: [
+    { required: true, message: '请输入审判人', trigger: 'change' },
+  ],
+  applicant_remark: [
+    { required: true, message: '请输入备注', trigger: 'change' },
+  ],
+};
+
+
 // 自动填充用户信息
 onMounted(() => {
 	try {
@@ -200,5 +223,5 @@ function onSubmit() {
 		}
 	});
 }
-const rules = {};
+
 </script>

+ 6 - 5
src/views/system/borrow/index.vue

@@ -2,7 +2,7 @@
 	<fs-page class="borrow-page"> 
 		<fs-crud ref="crudRef" v-bind="crudBinding" />
 		<BorrowTypeSelect v-model:visible="showBorrowTypeDialog" @select="onBorrowTypeSelected" />
-		<CommonBorrow v-if="showCommonBorrowDialog" v-model:visible="showCommonBorrowDialog" :modelValue="borrowForm" @submit="handleBorrowSubmit" />
+		<!-- <CommonBorrow v-if="showCommonBorrowDialog" v-model:visible="showCommonBorrowDialog" :modelValue="borrowForm" @submit="handleBorrowSubmit" /> -->
 		<ClassroomBorrow
 			v-if="showClassroomBorrowDialog"
 			v-model:visible="showClassroomBorrowDialog"
@@ -19,15 +19,15 @@ import { createCrudOptions } from './crud';
 // import { GetPermission } from './api';
 // import { handleColumnPermission } from '/@/utils/columnPermission';
 import BorrowTypeSelect from './component/BorrowTypeSelect/index.vue';
-import CommonBorrow from './component/CommonBorrow/index.vue';
+// import CommonBorrow from './component/CommonBorrow/index.vue';
 import ClassroomBorrow from './component/ClassroomBorrow/index.vue';
-import SpecialBorrow from './component/SpecialBorrow/index-back.vue';
+import SpecialBorrow from './component/SpecialBorrow/index.vue';
 import * as api from './api';
 import { ElMessage } from 'element-plus';
 
 const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions });
 const showBorrowTypeDialog = ref(false);
-const showCommonBorrowDialog = ref(false);
+// const showCommonBorrowDialog = ref(false);
 const showClassroomBorrowDialog = ref(false);
 const showSpecialBorrowDialog = ref(false);
 const borrowForm = ref({});
@@ -37,7 +37,8 @@ function onBorrowTypeSelected(type: number, mode: 'view' | 'edit' | 'add') {
 	// 初始化表单数据,带上所选借用性质
 	borrowForm.value = { borrow_type: type, mode: mode };
 	if (type == 0) {
-		showCommonBorrowDialog.value = true;
+		// showCommonBorrowDialog.value = true;
+		
 	} else if (type == 1) {
 		showClassroomBorrowDialog.value = true;
 	} else {

+ 85 - 50
src/views/system/borrow/workflow/WorkflowDialog/index.vue

@@ -152,7 +152,7 @@
 								</el-button>
 							</div>
 							<div class="addRole" style="width: 100%; display: flex; justify-content: center">
-								<el-button type="primary" size="small" @click="addRole(idx)">
+								<el-button type="primary" size="small" @click="addRole(idx)"  :disabled="step.roles.length >= 5">
 									<el-icon><Plus /></el-icon> 添加角色
 								</el-button>
 							</div>
@@ -162,7 +162,7 @@
 				</div>
 				<!-- 添加步骤按钮 -->
 				<div style="text-align: center; margin: 16px 0">
-					<el-button type="primary" @click="addStep">
+					<el-button type="primary" @click="addStep" :disabled="form.steps.length >= 5">
 						<el-icon><Plus /></el-icon> 添加审批步骤
 					</el-button>
 				</div>
@@ -330,12 +330,21 @@ watch(
 );
 
 function addStep() {
+	if (form.steps.length >= 5) {
+      ElMessage.warning('最多只能添加 5 个审批步骤');
+      return;
+    }
 	form.steps.push(defaultStep());
 }
 function removeStep(idx: number) {
 	if (form.steps.length > 1) form.steps.splice(idx, 1);
 }
 function addRole(stepIdx: number) {
+	const step = form.steps[stepIdx];
+    if (step.roles.length >= 5) {
+		ElMessage.warning('每个步骤最多只能添加 5 个角色');
+		return;
+    }
 	form.steps[stepIdx].roles.push(defaultRole());
 }
 function removeRole(stepIdx: number, roleIdx: number) {
@@ -345,25 +354,11 @@ function onCancel() {
 	visible.value = false;
 }
 
-// function onRoleChange(stepIdx: number, roleIdx: number, selectedValue: string) {
-//   const firstpayload = {
-//     workflow: "1",
-//     step_name: selectedValue,
-//   };
-//   // eslint-disable-next-line no-console
-//   console.log("选中的角色名:", selectedValue);
-//   // eslint-disable-next-line no-console
-//   console.log("构造的 payload:", firstpayload);
-// }
-
-// const passTypeMap: Record<string, string> = {
-//   any: "1", // 多人审核(任一通过)
-//   all: "2", // 多人审核(全部通过)
-//   single: "0", // 单人审核(你可以自定义触发条件)
-//   department: "3", // 部门负责人审核
-//   role: "4",       // 角色审核
-//   auto: "5",       // 自动审核
-// };
+
+const roleNameToId: { [key: string]: number } = {
+  '管理员': 1,
+  '指导老师': 2
+};
 
 
 async function onSave() {
@@ -373,7 +368,7 @@ async function onSave() {
 		} catch (err) {
 		// eslint-disable-next-line no-console
 		console.warn('表单验证失败:', err);
-		return; // 阻止后续提交
+		return; 
 		}
 
 	// 组装接口需要的数据
@@ -390,50 +385,90 @@ async function onSave() {
 		},
 	};
 	// eslint-disable-next-line no-console
-	console.log(payload);
+	// console.log(payload);
 	//创建审批
 	const res = await api.AddObj(payload);
-	// 提取返回的 ID
 	const workflowId = res?.data?.id;
 	if (!workflowId) {
 		ElMessage.error('未能获取流程 ID');
 		return;
 	}
 
-	// ✅ 获取用户选择的角色名
-	const selectedRoleNames = form.steps
-    .flatMap(step => step.roles.map(role => role.name))
-    .filter(name => !!name);
-	const selectedPassTypes = form.steps
-	.flatMap(step => step.roles.map(role => role.passType));
-
-	//组装审核接口
-	const firstpayload={
-		workflow: String(workflowId),
-		step_name: String(selectedRoleNames),
-		step_order: 1,
-		step_type: String(selectedPassTypes),
-		description:"由指导老师进行初审",
-		approvers: [1],  // 指定审核人ID列表,可选
-		approver_roles: [1],  // 审核角色ID列表,可选
-		approver_depts: [],  // 审核部门ID列表,可选
-		approval_conditions: {  // 审核条件,可以为空
-			required_fields: [],  // 必填字段
-			value_ranges: {}  // 字段值范围限制
-		},
-		timeout_hours: 24,  // 超时时间(小时)
-		timeout_action: "auto_reject",  // 超时处理:auto_approve=自动通过,auto_reject=自动拒绝,escalate=升级处理
-		is_active: true  // 是否启用:true=启用,false=禁用
 
+	for (let i = 0; i < form.steps.length; i++) {
+		const step = form.steps[i];
+		const stepOrder = i + 1;
+
+		const roleNames = step.roles.map(role => role.name).filter(Boolean);
+		const passTypes = step.roles.map(role => role.passType).filter(Boolean);
+
+		const stepType = passTypes[0] || '1';
+
+		const approverRoles = roleNames.map(name => roleNameToId[name]).filter(Boolean);
+
+		const stepPayload = {
+			workflow: String(workflowId),
+			step_name: `${roleNames.join(',')}审批`,
+			step_order: stepOrder,
+			step_type: stepType,
+			description: `由${roleNames.join(',')}进行审批`,
+			approvers: [1],  // 可选:你可以根据需要填入具体 ID
+			approver_roles: approverRoles,
+			approver_depts: [],
+			approval_conditions: {
+				required_fields: [],
+				value_ranges: {}
+			},
+			timeout_hours: 24,
+			timeout_action: "auto_reject",
+			is_active: true
 	};
+
 	// eslint-disable-next-line no-console
-	console.log(firstpayload);
-	await api.AddFirstObj(firstpayload);
+	console.log(`步骤 ${stepOrder} payload`, stepPayload);
+
+	await api.AddFirstObj(stepPayload);
+	}
+
+
+
+	// const selectedRoleNames = form.steps
+    // .flatMap(step => step.roles.map(role => role.name))
+    // .filter(name => !!name);
+	// const selectedPassTypes = form.steps
+	// .flatMap(step => step.roles.map(role => role.passType));
+
+	// //组装审核接口
+	// const firstpayload={
+	// 	workflow: String(workflowId),
+	// 	step_name: String(selectedRoleNames),
+	// 	step_order: 1,
+	// 	step_type: String(selectedPassTypes),
+	// 	description:"由指导老师进行初审",
+	// 	approvers: [1],  // 指定审核人ID列表,可选
+	// 	approver_roles: [1],  // 审核角色ID列表,可选
+	// 	approver_depts: [],  // 审核部门ID列表,可选
+	// 	approval_conditions: {  // 审核条件,可以为空
+	// 		required_fields: [],  // 必填字段
+	// 		value_ranges: {}  // 字段值范围限制
+	// 	},
+	// 	timeout_hours: 24,  // 超时时间(小时)
+	// 	timeout_action: "auto_reject",  // 超时处理:auto_approve=自动通过,auto_reject=自动拒绝,escalate=升级处理
+	// 	is_active: true  // 是否启用:true=启用,false=禁用
+
+	// };
+	// // eslint-disable-next-line no-console
+	// console.log(firstpayload);
+	// await api.AddFirstObj(firstpayload);
 
 	ElMessage.success('保存成功');
 	emit('success');
 	visible.value = false;
 }
+
+
+
+
 </script>
 
 <style scoped>

+ 2 - 2
src/views/system/borrow/workflow/curd.tsx

@@ -49,13 +49,13 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp
 				width: 220,
 				buttons: {
 					view: {
-						show: false,
+						show: true,
 						click: ({ row }) => {
 							window.dispatchEvent(new CustomEvent('workflow-view', { detail: row }));
 						},
 					},
 					edit: {
-						show: true,
+						show: false,
 						click: ({ row }) => {
 							window.dispatchEvent(new CustomEvent('workflow-edit', { detail: row }));
 						},

+ 119 - 43
src/views/system/device/crud.tsx

@@ -1,10 +1,15 @@
-import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, uiContext, UserPageQuery } from '@fast-crud/fast-crud';
+import { AddReq, compute, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, uiContext, UserPageQuery } from '@fast-crud/fast-crud';
 import dayjs from 'dayjs';
 import * as api from './api';
 import { uploadFile } from './api';
 import { auth } from '/@/utils/authFunction';
 import { commonCrudConfig } from '/@/utils/commonCrud';
-
+import {request} from '/@/utils/service';
+import {getBaseURL} from '/@/utils/baseUrl';
+import Cookies from 'js-cookie';
+import { successMessage } from '/@/utils/message';
+import { dictionary } from '/@/utils/dictionary';
+import { APIResponseData } from '../columns/types';
 
 export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProps): CreateCrudOptionsRet {
 	const pageRequest = async (query: UserPageQuery) => {
@@ -36,6 +41,25 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp
 			toolbar:{
 				show:false,
 			},
+			rowHandle: {
+				fixed: 'right',
+				width: 220,
+				view: {
+					show: true,
+					click: ({ row }) => {
+						window.dispatchEvent(new CustomEvent('workflow-view', { detail: row }));
+					},
+				},
+				edit: {
+					show: true,
+					click: ({ row }) => {
+						window.dispatchEvent(new CustomEvent('workflow-edit', { detail: row }));
+					},
+				},
+				remove: {
+					show: true,
+				},
+			},
 			actionbar: {
                 buttons: {
                     add: {
@@ -134,6 +158,17 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp
 						rules: [{ required: true, message: '请选择设备状态' }],
 					},
 				},
+				borrowed_quantity:{
+					title:"已借出",
+					type:'input',
+					search:{show:false},
+					column: { minWidth: 100 },
+					form: {
+						show:false,
+						component: { placeholder: '请输入已借出' },
+						rules: [{ required: true, message: '请输入已借出' }],
+					},
+				},
 				brand:{
 					title:'品牌',
 					type:"input",
@@ -157,7 +192,19 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp
 					title:'库存数量',
 					type:"input",
 					column: { minWidth: 100 },
-					from:{show: false}
+					addForm:{
+						show:false,
+					},
+					viewForm:{
+						show:false,
+					},
+					editForm:{show:false},
+					from:{ 
+						show:false,
+						component: { placeholder: '请输入已借出' },
+						rules: [{ required: true, message: '请输入已借出' }],
+
+					}
 				},
 				warehouse:{
 					title:'库存仓库',
@@ -174,17 +221,26 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp
 				},
 				is_visible:{
 					title:'是否可见',
-					type:"dict-select",
-					column: { minWidth: 120 },
+					type: 'dict-radio',
+					column: {
+						minWidth: 90,
+						component: {
+							name: 'fs-dict-switch',
+							activeText: '',
+							inactiveText: '',
+							style: '--el-switch-on-color: var(--el-color-primary); --el-switch-off-color: #dcdfe6',
+							onChange: compute((context) => {
+								return () => {
+									api.UpdateObj(context.row).then((res:APIResponseData) => {
+										successMessage(res.msg as string);
+									});
+								};
+							}),
+						},
+					},
 					dict: dict({
-						data: [
-							{ label: '可见', value: true },
-							{ label: '隐藏', value: false },
-						],
+						data: dictionary('button_status_bool'),
 					}),
-					form: {
-						component: { placeholder: '请输入是否可见' }
-					}
 
 				},
 				
@@ -274,27 +330,47 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp
 							uploader: {
 								type: 'form',
 								limit: 1,
+								action: '/api/system/device/upload-image/',
 								accept: ".jpg,.png",
-								// uploadRequest: uploadRequestHandler,
-								// uploadRequest: async (file) => {
-								// // eslint-disable-next-line no-console
-								// // console.log("files::",file);
-								// const previewUrl = URL.createObjectURL(file.file);
-								// file.value=previewUrl;
-								// const formData = new FormData();
-								// formData.append('image', file.file);
-								// // eslint-disable-next-line no-console
-								// // console.log("files::",file);
-								// const res = await uploadFile(formData);			
-								// // eslint-disable-next-line no-console
-								// console.log("url::"+res.data.image_url);
-								// file.value = res.data.image_url; // 绑定表单字段
-								// // const testurl="http://58.34.94.147:8086/media/files/3/c/3c711548de2284d59922379243a60bd8.png";
-								// // const apiUrl = import.meta.env.VITE_API_URL;
-								// // const res = await axios.post(`${import.meta.env.VITE_API_URL}/api/system/device/upload-image/`, formData);
-								// return {url: "http://58.34.94.147:8086/media/files/3/c/3c711548de2284d59922379243a60bd8.png"}    // 必须返回包含url的对象
-								// }
+								uploadRequest: async ({ action, file, onProgress }) => {
+									const token = Cookies.get('token'); 
+									// eslint-disable-next-line no-console
+									console.log("token:::",token);
+									const data = new FormData();
+									data.append("image", file);
+									return await request({
+										url: action,
+										method: "post",
+										timeout: 60000,
+										headers: {
+										"Content-Type": "multipart/form-data",
+										"Authorization": token ? `JWT ${token}` : ''
+										},
+										data,
+										onUploadProgress: (p) => {
+										onProgress({ percent: Math.round((p.loaded / p.total) * 100) });
+										}
+									});
+								},
+								successHandle(ret) {
+									// eslint-disable-next-line no-console
+									console.log("ret.data.image_url:::",ret.data.image_url);
+
+									return {
+										url: getBaseURL(ret.data.image_url), 
+										key: ret.data.id,
+										...ret.data
+									};
+								},
+								valueBuilder({ row, key }) {
+									return row[key] ? [row[key]] : [];
+								},
+								valueResolve({ form, key }) {
+									form[key] = Array.isArray(form[key]) ? form[key][0] : form[key];
+								}
+								
 
+								
 							}
 						}
 					}
@@ -378,16 +454,16 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp
 						},
 					}
 				},
-				maintenancename: {
-					title: '维修名称',
-					type: 'input',
-					search: { show: false },
-					column: { show:false,minWidth: 100 },
-					form: {
-						component: { placeholder: '请输入设备购入价格' },
-						rules: [{ required: true, message: '请输入设备购入价格' }],
-					},
-				},
+				// maintenancename: {
+				// 	title: '维修名称',
+				// 	type: 'input',
+				// 	search: { show: false },
+				// 	column: { show:false,minWidth: 100 },
+				// 	form: {
+				// 		component: { placeholder: '请输入设备购入价格' },
+				// 		rules: [{ required: true, message: '请输入设备购入价格' }],
+				// 	},
+				// },
 				...commonCrudConfig({
 					create_datetime: { search: false },
 					update_datetime: { search: false },
@@ -411,7 +487,7 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp
 						}
 					},
 						icon: "el-icon-goods",
-						columns: ["code","category_name", "name", "status","brand","specification","serial_number","total_quantity","warehouse","is_visible","department","purchase_date","supplier","price","warranty_expiration","image","tenant_id","category","quantity","tags"]
+						columns: ["code","category_name", "name", "status","borrowed_quantity","brand","specification","serial_number","warehouse","is_visible","department","purchase_date","supplier","price","warranty_expiration","image","tenant_id","category","quantity","tags"]
 					},
 					borrow: {
 						label: "借用记录",
@@ -422,7 +498,7 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp
 						label: "维修记录",
 						collapsed: true, //默认折叠
 						icon: "el-icon-warning-outline",
-						columns: ["maintenancename"]
+						columns: [""]
 					},
 					maintain: {
 						label: "保养记录",

+ 3 - 3
src/views/system/suppliermanage/crud.tsx

@@ -200,6 +200,7 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp
 				tenant_id:{
 					title: '租户id',
 					type: 'dict-select',
+					tenant_id:1,
 					column: {
 						show:false,
 						minWidth: 120,
@@ -208,11 +209,10 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp
 						url: '/api/system/tenant/list/',
 						value: 'id', 
 						label: 'name',
-						 
 					}),
 					form: {	
 						show:false,
-						value:'1',
+						value: 1,
 						component: { placeholder: '请填租户id' },
 						rules: [{ required: false, message: '请填租户id' }],
 					},
@@ -230,7 +230,7 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp
 					}),
 					column: { minWidth: 100 },
 					form: {
-						show:false,
+						show:true,
 						value:true,
 						component: { placeholder: '请选择状态' },
 						rules: [{ required: true, message: '请选择状态' }],

+ 0 - 54
src/views/system/timetablemanage/index.vue

@@ -139,7 +139,6 @@ function openDialogEdit(course?: any) {
 	// eslint-disable-next-line no-console
 	console.log('course:::::', course);
 	if (!course) {
-		// 新建
 		dialogRef.value.open({
 		class_date: dayjs().format('YYYY-MM-DD'),
 		time: 1,
@@ -151,49 +150,6 @@ function openDialogEdit(course?: any) {
 }
 
 
-// function handleCellClick(row: any, dayIndex: number) {
-// 	const classText = row[`day${dayIndex + 1}`];
-// 	// eslint-disable-next-line no-console
-// 	console.log('classText:::::', classText);
-// 	const timeIndex = timeLabels.value.indexOf(row.timeLabel) + 1;
-// 	if (!classText || classText.length === 0) {
-// 		openDialog({
-//         class_date: dayjs().startOf('isoWeek').add(dayIndex, 'day').format('YYYY-MM-DD'),
-//         time: timeIndex,
-//       });
-// 	}
-// 	else if (classText.length === 1) {
-//       openDialog(classText[0]);
-//     } else {
-// 		selectedCourses.value = classText;
-// 		courseSelectVisible.value = true;
-//     }
-
-//   } else {
-
-//     openDialog({
-//       class_date: dayjs().startOf('isoWeek').add(dayIndex, 'day').format('YYYY-MM-DD'),
-//       time: timeLabels.value.indexOf(row.timeLabel) + 1,
-//       classdetail: '高等数学',
-//       teacher: 13,
-//       semester: 1,
-//       grade: 1,
-//       class_number: row.id,
-//       classroom: 'A101',
-//       total_lessons: 48
-//     });
-//   }
-// }
-
-
-// const weekDates = computed(() => {
-//   const monday = dayjs().startOf('isoWeek').add(weekOffset.value, 'week')
-//   return Array.from({ length: 7 }, (_, i) => {
-//     const date = monday.add(i, 'day')
-//     return `${['周一','周二','周三','周四','周五','周六','周日'][i]} (${date.format('MM.DD')})`
-//   })
-// })
-
 function nextWeek() {
   if (currentWeek.value + weekOffset.value < totalWeeks.value){
 	weekOffset.value++;
@@ -213,16 +169,6 @@ const headerStyle = {
 }
 
 
-
-// const periodLabels = [
-//   '第一节', '第二节', '第三节', '第四节', '第五节',
-//   '第六节', '第七节', '第八节', '第九节', '第十节'
-// ]
-// function getPeriodLabel(index: number): string {
-//   return periodLabels[index] || `第${index + 1}节`
-// }
-
-
 const scheduleData = ref<any[]>([])
 
 const weekDates = ref<string[]>([]);