&(int*)0 / &((type*)0)->member 记录一下

本文详细解析了Linux内核中常用的list_entry宏的功能与用法,该宏通过结构体成员指针找到其容器的指针,是理解Linux链表操作的关键。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#define list_entry(ptr, type, member)
((type*)((char*)(ptr)-(unsigned long)(&((type*)0)->member)))

的作用、功能。

该方法就是 通过 type类型结构体 的 成员变量 member 的地址 去获取 该结构体的地址。。
而 (unsigned long)(&((type*)0)->member) type类型结构体 中 成员变量 member 的地址在该结构体中的偏移量。。

我把问题简化一下。 (type*)0 的作用、功能。

C语言中 (type*)X 表示将操作 X 强制类型转换为 type* 类型(即 type* 类型指针)。
这里是将 0 强制类型转换为 type* 类型, 0 成为 type* 类型。
一个指向 NULL 的 type* 类型 指针 和 这里的 (type*)0 是等价的(ansi/iso-c99 标准规定 NULL 指针为 0x00000000, 即内存中的“第 0 号地址”)。

到这里,大家应该可以明白,上面的 list_entry 的意思了吧? 这个是 unix / linux 里有 _list.h 文件的。

Linux内核中,获取节点地址的函数list_entry()非常常用,由于其定义有点晦涩,先解析如下:

list_entry的宏定义:
#define list_entry(ptr, type, member) /
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
这个倒是不难理解:从一个结构的成员指针找到其容器的指针。
但是正因为如此,我的第一感觉是,这个宏的名字应该更加抽象,名字似乎应该改称叫“寻找容器”一类的,查看list.h源代码,发现现在的定义是这样的:
#define list_entry(ptr, type, member) /
container_of(ptr, type, member)

#define container_of(ptr, type, member) /
({ /
const typeof( ((type *)0)->member ) *__mptr = (ptr);/
(type *)( (char *)__mptr - offsetof(type,member) ); /
})

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE )0)->MEMBER)
linux不想用C++,但又想利用C++的优点,如是出现了很多奇怪的宏,他们叫做trick。
ptr是找容器的那个变量的指针,把它减去自己在容器中的偏移量的值就应该 得到容器的指针。(容器就是包含自己的那个结构)。指针的加减要注意类型,用(char
)ptr是为了计算字节偏移。((type *)0)->member是一个小技巧。自己理解吧。前面的(type *)再转回容器的类型。

#define list_entry(ptr, type, member) /
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))

ptr是指向list_head类型链表的指针,type为一个结构,而member为结构type中的一个域,类型为list_head,这个宏返回指向type结构的指针。在内核代码中大量引用了这个宏,因此,搞清楚这个宏的含义和用法非常重要。

设有如下结构体定义:
typedef struct xxx
{
……(结构体中其他域,令其总大小为size1)
type1 member;
……(结构体中其他域)
}type;

定义变量:
type a;
type * b;
type1 * ptr;
执行:
ptr=&(a.member);
b=list_entry(ptr,type,member);
则可使b指向a,得到了a的地址。

如何做到的呢?

先看&((type *)0)->member:
把“0”强制转化为指针类型,则该指针一定指向“0”(数据段基址)。因为指针是“type *”型的,所以可取到以“0”为基地址的一个type型变量member域的地址。那么这个地址也就等于member域到结构体基地址的偏移字节数。

再来看 ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))):
(char *)(ptr)使得指针的加减操作步长为一字节,(unsigned long)(&((type *)0)->member)等于ptr指向的member到该member所在结构体基地址的偏移字节数。二者一减便得出该结构体的地址。转换为 (type *)型的指针,大功告成。

==============

list_entry定义如下:

/**

  • list_entry - get the struct for this entry
  • @ptr: the &struct list_head pointer.
  • @type: the type of the struct this is embedded in.
  • @member: the name of the list_struct within the struct.
    */
    #define list_entry(ptr, type, member) /
    ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
/**************************************************************************** * drivers/sensors/sensor.c * * SPDX-License-Identifier: Apache-2.0 * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. The * ASF licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include <nuttx/config.h> #include <sys/types.h> #include <stdbool.h> #include <stdio.h> #include <string.h> #include <assert.h> #include <errno.h> #include <debug.h> #include <poll.h> #include <fcntl.h> #include <nuttx/list.h> #include <nuttx/kmalloc.h> #include <nuttx/circbuf.h> #include <nuttx/mutex.h> #include <nuttx/sensors/sensor.h> #include <nuttx/lib/lib.h> /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ /* Device naming ************************************************************/ #define ROUND_DOWN(x, y) (((x) / (y)) * (y)) #define DEVNAME_FMT "/dev/uorb/sensor_%s%s%d" #define DEVNAME_UNCAL "_uncal" #define TIMING_BUF_ESIZE (sizeof(uint32_t)) /**************************************************************************** * Private Types ****************************************************************************/ struct sensor_axis_map_s { int8_t src_x; int8_t src_y; int8_t src_z; int8_t sign_x; int8_t sign_y; int8_t sign_z; }; /* This structure describes sensor meta */ struct sensor_meta_s { size_t esize; FAR char *name; }; typedef enum sensor_role_e { SENSOR_ROLE_NONE, SENSOR_ROLE_WR, SENSOR_ROLE_RD, SENSOR_ROLE_RDWR, } sensor_role_t; /* This structure describes user info of sensor, the user may be * advertiser or subscriber */ struct sensor_user_s { /* The common info */ struct list_node node; /* Node of users list */ struct pollfd *fds; /* The poll structure of thread waiting events */ sensor_role_t role; /* The is used to indicate user's role based on open flags */ bool changed; /* This is used to indicate event happens and need to * asynchronous notify other users */ unsigned int event; /* The event of this sensor, eg: SENSOR_EVENT_FLUSH_COMPLETE. */ bool flushing; /* The is used to indicate user is flushing */ sem_t buffersem; /* Wakeup user waiting for data in circular buffer */ size_t bufferpos; /* The index of user generation in buffer */ /* The subscriber info * Support multi advertisers to subscribe their own data when they * appear in dual role */ struct sensor_ustate_s state; }; /* This structure describes the state of the upper half driver */ struct sensor_upperhalf_s { FAR struct sensor_lowerhalf_s *lower; /* The handle of lower half driver */ struct sensor_state_s state; /* The state of sensor device */ struct circbuf_s timing; /* The circular buffer of generation */ struct circbuf_s buffer; /* The circular buffer of data */ rmutex_t lock; /* Manages exclusive access to file operations */ struct list_node userlist; /* List of users */ }; /**************************************************************************** * Private Function Prototypes ****************************************************************************/ static void sensor_pollnotify(FAR struct sensor_upperhalf_s *upper, pollevent_t eventset, sensor_role_t role); static int sensor_open(FAR struct file *filep); static int sensor_close(FAR struct file *filep); static ssize_t sensor_read(FAR struct file *filep, FAR char *buffer, size_t buflen); static ssize_t sensor_write(FAR struct file *filep, FAR const char *buffer, size_t buflen); static int sensor_ioctl(FAR struct file *filep, int cmd, unsigned long arg); static int sensor_poll(FAR struct file *filep, FAR struct pollfd *fds, bool setup); static ssize_t sensor_push_event(FAR void *priv, FAR const void *data, size_t bytes); /**************************************************************************** * Private Data ****************************************************************************/ static const struct sensor_axis_map_s g_remap_tbl[] = { { 0, 1, 2, 1, 1, 1 }, /* P0 */ { 1, 0, 2, 1, -1, 1 }, /* P1 */ { 0, 1, 2, -1, -1, 1 }, /* P2 */ { 1, 0, 2, -1, 1, 1 }, /* P3 */ { 0, 1, 2, -1, 1, -1 }, /* P4 */ { 1, 0, 2, -1, -1, -1 }, /* P5 */ { 0, 1, 2, 1, -1, -1 }, /* P6 */ { 1, 0, 2, 1, 1, -1 }, /* P7 */ }; static const struct sensor_meta_s g_sensor_meta[] = { {0, NULL}, {sizeof(struct sensor_accel), "accel"}, {sizeof(struct sensor_mag), "mag"}, {sizeof(struct sensor_orientation), "orientation"}, {sizeof(struct sensor_gyro), "gyro"}, {sizeof(struct sensor_light), "light"}, {sizeof(struct sensor_baro), "baro"}, {sizeof(struct sensor_noise), "noise"}, {sizeof(struct sensor_prox), "prox"}, {sizeof(struct sensor_rgb), "rgb"}, {sizeof(struct sensor_accel), "linear_accel"}, {sizeof(struct sensor_rotation), "rotation"}, {sizeof(struct sensor_humi), "humi"}, {sizeof(struct sensor_temp), "temp"}, {sizeof(struct sensor_pm25), "pm25"}, {sizeof(struct sensor_pm1p0), "pm1p0"}, {sizeof(struct sensor_pm10), "pm10"}, {sizeof(struct sensor_event), "motion_detect"}, {sizeof(struct sensor_event), "step_detector"}, {sizeof(struct sensor_step_counter), "step_counter"}, {sizeof(struct sensor_ph), "ph"}, {sizeof(struct sensor_hrate), "hrate"}, {sizeof(struct sensor_event), "tilt_detector"}, {sizeof(struct sensor_event), "wake_gesture"}, {sizeof(struct sensor_event), "glance_gesture"}, {sizeof(struct sensor_event), "pickup_gesture"}, {sizeof(struct sensor_event), "wrist_tilt"}, {sizeof(struct sensor_orientation), "device_orientation"}, {sizeof(struct sensor_pose_6dof), "pose_6dof"}, {sizeof(struct sensor_gas), "gas"}, {sizeof(struct sensor_event), "significant_motion"}, {sizeof(struct sensor_hbeat), "hbeat"}, {sizeof(struct sensor_force), "force"}, {sizeof(struct sensor_hall), "hall"}, {sizeof(struct sensor_event), "offbody_detector"}, {sizeof(struct sensor_uv), "uv"}, {sizeof(struct sensor_angle), "hinge_angle"}, {sizeof(struct sensor_ir), "ir"}, {sizeof(struct sensor_hcho), "hcho"}, {sizeof(struct sensor_tvoc), "tvoc"}, {sizeof(struct sensor_dust), "dust"}, {sizeof(struct sensor_ecg), "ecg"}, {sizeof(struct sensor_ppgd), "ppgd"}, {sizeof(struct sensor_ppgq), "ppgq"}, {sizeof(struct sensor_impd), "impd"}, {sizeof(struct sensor_ots), "ots"}, {sizeof(struct sensor_co2), "co2"}, {sizeof(struct sensor_cap), "cap"}, {sizeof(struct sensor_eng), "eng"}, {sizeof(struct sensor_gnss), "gnss"}, {sizeof(struct sensor_gnss_satellite), "gnss_satellite"}, {sizeof(struct sensor_gnss_measurement), "gnss_measurement"}, {sizeof(struct sensor_gnss_clock), "gnss_clock"}, {sizeof(struct sensor_gnss_geofence_event), "gnss_geofence_event"}, }; static const struct file_operations g_sensor_fops = { sensor_open, /* open */ sensor_close, /* close */ sensor_read, /* read */ sensor_write, /* write */ NULL, /* seek */ sensor_ioctl, /* ioctl */ NULL, /* mmap */ NULL, /* truncate */ sensor_poll /* poll */ }; /**************************************************************************** * Private Functions ****************************************************************************/ static void sensor_lock(FAR void *priv) { FAR struct sensor_upperhalf_s *upper = priv; nxrmutex_lock(&upper->lock); } static void sensor_unlock(FAR void *priv) { FAR struct sensor_upperhalf_s *upper = priv; nxrmutex_unlock(&upper->lock); } static int sensor_update_interval(FAR struct file *filep, FAR struct sensor_upperhalf_s *upper, FAR struct sensor_user_s *user, uint32_t interval) { FAR struct sensor_lowerhalf_s *lower = upper->lower; FAR struct sensor_user_s *tmp; uint32_t min_interval = interval; uint32_t min_latency = interval != UINT32_MAX ? user->state.latency : UINT32_MAX; int ret = 0; if (interval == user->state.interval) { return 0; } list_for_every_entry(&upper->userlist, tmp, struct sensor_user_s, node) { if (tmp == user || tmp->state.interval == UINT32_MAX) { continue; } if (min_interval > tmp->state.interval) { min_interval = tmp->state.interval; } if (min_latency > tmp->state.latency) { min_latency = tmp->state.latency; } } if (lower->ops->set_interval) { if (min_interval != UINT32_MAX && min_interval != upper->state.min_interval) { uint32_t expected_interval = min_interval; ret = lower->ops->set_interval(lower, filep, &min_interval); if (ret < 0) { return ret; } else if (min_interval > expected_interval) { return -EINVAL; } } if (min_latency == UINT32_MAX) { min_latency = 0; } if (lower->ops->batch && (min_latency != upper->state.min_latency || (min_interval != upper->state.min_interval && min_latency))) { ret = lower->ops->batch(lower, filep, &min_latency); if (ret >= 0) { upper->state.min_latency = min_latency; } } } upper->state.min_interval = min_interval; user->state.interval = interval; sensor_pollnotify(upper, POLLPRI, SENSOR_ROLE_WR); return ret; } static int sensor_update_latency(FAR struct file *filep, FAR struct sensor_upperhalf_s *upper, FAR struct sensor_user_s *user, uint32_t latency) { FAR struct sensor_lowerhalf_s *lower = upper->lower; FAR struct sensor_user_s *tmp; uint32_t min_latency = latency; int ret = 0; if (latency == user->state.latency) { return 0; } if (user->state.interval == UINT32_MAX) { user->state.latency = latency; return 0; } if (latency <= upper->state.min_latency) { goto update; } list_for_every_entry(&upper->userlist, tmp, struct sensor_user_s, node) { if (tmp == user || tmp->state.interval == UINT32_MAX) { continue; } if (min_latency > tmp->state.latency) { min_latency = tmp->state.latency; } } update: if (min_latency == UINT32_MAX) { min_latency = 0; } if (min_latency == upper->state.min_latency) { user->state.latency = latency; return ret; } if (lower->ops->batch) { ret = lower->ops->batch(lower, filep, &min_latency); if (ret < 0) { return ret; } } upper->state.min_latency = min_latency; user->state.latency = latency; sensor_pollnotify(upper, POLLPRI, SENSOR_ROLE_WR); return ret; } static void sensor_generate_timing(FAR struct sensor_upperhalf_s *upper, unsigned long nums) { uint32_t interval = upper->state.min_interval != UINT32_MAX ? upper->state.min_interval : 1; while (nums-- > 0) { upper->state.generation += interval; circbuf_overwrite(&upper->timing, &upper->state.generation, TIMING_BUF_ESIZE); } } static bool sensor_is_updated(FAR struct sensor_upperhalf_s *upper, FAR struct sensor_user_s *user) { long delta = (long long)upper->state.generation - user->state.generation; if (delta <= 0) { return false; } else if (user->state.interval == UINT32_MAX) { return true; } else { /* Check whether next generation user want in buffer. * generation next generation(not published yet) * ____v_____________v * ////|//////^ | * ^ middle point * next generation user want */ return delta >= user->state.interval - (upper->state.min_interval >> 1); } } static void sensor_catch_up(FAR struct sensor_upperhalf_s *upper, FAR struct sensor_user_s *user) { uint32_t generation; long delta; circbuf_peek(&upper->timing, &generation, TIMING_BUF_ESIZE); delta = (long long)generation - user->state.generation; if (delta > 0) { user->bufferpos = upper->timing.tail / TIMING_BUF_ESIZE; if (user->state.interval == UINT32_MAX) { user->state.generation = generation - 1; } else { delta -= upper->state.min_interval >> 1; user->state.generation += ROUND_DOWN(delta, user->state.interval); } } } static ssize_t sensor_do_samples(FAR struct sensor_upperhalf_s *upper, FAR struct sensor_user_s *user, FAR char *buffer, size_t len) { uint32_t generation; ssize_t ret = 0; size_t nums; size_t pos; size_t end; sensor_catch_up(upper, user); nums = upper->timing.head / TIMING_BUF_ESIZE - user->bufferpos; if (len < nums * upper->state.esize) { nums = len / upper->state.esize; } len = nums * upper->state.esize; /* Take samples continuously */ if (user->state.interval == UINT32_MAX) { if (buffer != NULL) { ret = circbuf_peekat(&upper->buffer, user->bufferpos * upper->state.esize, buffer, len); } else { ret = len; } user->bufferpos += nums; circbuf_peekat(&upper->timing, (user->bufferpos - 1) * TIMING_BUF_ESIZE, &user->state.generation, TIMING_BUF_ESIZE); return ret; } /* Take samples one-bye-one, to determine whether a sample needed: * * If user's next generation is on the left side of middle point, * we should copy this sample for user. * next_generation(or end) * ________________v____ * timing buffer: //|//////. | * ^ middle * generation * next sample(or end) * ________________v____ * data buffer: | | * ^ * sample */ pos = user->bufferpos; end = upper->timing.head / TIMING_BUF_ESIZE; circbuf_peekat(&upper->timing, pos * TIMING_BUF_ESIZE, &generation, TIMING_BUF_ESIZE); while (pos++ != end) { uint32_t next_generation; long delta; if (pos * TIMING_BUF_ESIZE == upper->timing.head) { next_generation = upper->state.generation + upper->state.min_interval; } else { circbuf_peekat(&upper->timing, pos * TIMING_BUF_ESIZE, &next_generation, TIMING_BUF_ESIZE); } delta = next_generation + generation - ((user->state.generation + user->state.interval) << 1); if (delta >= 0) { if (buffer != NULL) { ret += circbuf_peekat(&upper->buffer, (pos - 1) * upper->state.esize, buffer + ret, upper->state.esize); } else { ret += upper->state.esize; } user->bufferpos = pos; user->state.generation += user->state.interval; if (ret >= len) { break; } } generation = next_generation; } if (pos - 1 == end && sensor_is_updated(upper, user)) { generation = upper->state.generation - user->state.generation + (upper->state.min_interval >> 1); user->state.generation += ROUND_DOWN(generation, user->state.interval); } return ret; } static void sensor_pollnotify_one(FAR struct sensor_user_s *user, pollevent_t eventset, sensor_role_t role) { if (!(user->role & role)) { return; } if (eventset == POLLPRI) { user->changed = true; } poll_notify(&user->fds, 1, eventset); } static void sensor_pollnotify(FAR struct sensor_upperhalf_s *upper, pollevent_t eventset, sensor_role_t role) { FAR struct sensor_user_s *user; list_for_every_entry(&upper->userlist, user, struct sensor_user_s, node) { sensor_pollnotify_one(user, eventset, role); } } static int sensor_open(FAR struct file *filep) { FAR struct inode *inode = filep->f_inode; FAR struct sensor_upperhalf_s *upper = inode->i_private; FAR struct sensor_lowerhalf_s *lower = upper->lower; FAR struct sensor_user_s *user; int ret = 0; nxrmutex_lock(&upper->lock); user = kmm_zalloc(sizeof(struct sensor_user_s)); if (user == NULL) { ret = -ENOMEM; goto errout_with_lock; } if (lower->ops->open) { ret = lower->ops->open(lower, filep); if (ret < 0) { goto errout_with_user; } } if ((filep->f_oflags & O_DIRECT) == 0) { if (filep->f_oflags & O_RDOK) { if (upper->state.nsubscribers == 0 && lower->ops->activate) { ret = lower->ops->activate(lower, filep, true); if (ret < 0) { goto errout_with_open; } } user->role |= SENSOR_ROLE_RD; upper->state.nsubscribers++; } if (filep->f_oflags & O_WROK) { user->role |= SENSOR_ROLE_WR; upper->state.nadvertisers++; if (filep->f_oflags & SENSOR_PERSIST) { lower->persist = true; } } } if (upper->state.generation && lower->persist) { user->state.generation = upper->state.generation - 1; user->bufferpos = upper->timing.head / TIMING_BUF_ESIZE - 1; } else { user->state.generation = upper->state.generation; user->bufferpos = upper->timing.head / TIMING_BUF_ESIZE; } user->state.interval = UINT32_MAX; user->state.esize = upper->state.esize; nxsem_init(&user->buffersem, 0, 0); list_add_tail(&upper->userlist, &user->node); /* The new user generation, notify to other users */ sensor_pollnotify(upper, POLLPRI, SENSOR_ROLE_WR); filep->f_priv = user; goto errout_with_lock; errout_with_open: if (lower->ops->close) { lower->ops->close(lower, filep); } errout_with_user: kmm_free(user); errout_with_lock: nxrmutex_unlock(&upper->lock); return ret; } static int sensor_close(FAR struct file *filep) { FAR struct inode *inode = filep->f_inode; FAR struct sensor_upperhalf_s *upper = inode->i_private; FAR struct sensor_lowerhalf_s *lower = upper->lower; FAR struct sensor_user_s *user = filep->f_priv; int ret = 0; nxrmutex_lock(&upper->lock); if (lower->ops->close) { ret = lower->ops->close(lower, filep); if (ret < 0) { nxrmutex_unlock(&upper->lock); return ret; } } if ((filep->f_oflags & O_DIRECT) == 0) { if (filep->f_oflags & O_RDOK) { upper->state.nsubscribers--; if (upper->state.nsubscribers == 0 && lower->ops->activate) { lower->ops->activate(lower, filep, false); } } if (filep->f_oflags & O_WROK) { upper->state.nadvertisers--; } } list_delete(&user->node); sensor_update_latency(filep, upper, user, UINT32_MAX); sensor_update_interval(filep, upper, user, UINT32_MAX); nxsem_destroy(&user->buffersem); /* The user is closed, notify to other users */ sensor_pollnotify(upper, POLLPRI, SENSOR_ROLE_WR); nxrmutex_unlock(&upper->lock); kmm_free(user); return ret; } static ssize_t sensor_read(FAR struct file *filep, FAR char *buffer, size_t len) { FAR struct inode *inode = filep->f_inode; FAR struct sensor_upperhalf_s *upper = inode->i_private; FAR struct sensor_lowerhalf_s *lower = upper->lower; FAR struct sensor_user_s *user = filep->f_priv; ssize_t ret; if (!len) { return -EINVAL; } nxrmutex_lock(&upper->lock); if (lower->ops->fetch) { if (buffer == NULL) { return -EINVAL; } if (!(filep->f_oflags & O_NONBLOCK)) { nxrmutex_unlock(&upper->lock); ret = nxsem_wait_uninterruptible(&user->buffersem); if (ret < 0) { return ret; } nxrmutex_lock(&upper->lock); } else if (!upper->state.nsubscribers) { ret = -EAGAIN; goto out; } ret = lower->ops->fetch(lower, filep, buffer, len); } else if (circbuf_is_empty(&upper->buffer)) { ret = -ENODATA; } else if (sensor_is_updated(upper, user)) { ret = sensor_do_samples(upper, user, buffer, len); } else if (lower->persist) { if (buffer == NULL) { ret = upper->state.esize; } else { /* Persistent device can get latest old data if not updated. */ ret = circbuf_peekat(&upper->buffer, (user->bufferpos - 1) * upper->state.esize, buffer, upper->state.esize); } } else { ret = -ENODATA; } out: nxrmutex_unlock(&upper->lock); return ret; } static ssize_t sensor_write(FAR struct file *filep, FAR const char *buffer, size_t buflen) { FAR struct inode *inode = filep->f_inode; FAR struct sensor_upperhalf_s *upper = inode->i_private; FAR struct sensor_lowerhalf_s *lower = upper->lower; return lower->push_event(lower->priv, buffer, buflen); } static int sensor_ioctl(FAR struct file *filep, int cmd, unsigned long arg) { FAR struct inode *inode = filep->f_inode; FAR struct sensor_upperhalf_s *upper = inode->i_private; FAR struct sensor_lowerhalf_s *lower = upper->lower; FAR struct sensor_user_s *user = filep->f_priv; uint32_t arg1 = (uint32_t)arg; int ret = 0; switch (cmd) { case SNIOC_GET_STATE: { nxrmutex_lock(&upper->lock); memcpy((FAR void *)(uintptr_t)arg, &upper->state, sizeof(upper->state)); user->changed = false; nxrmutex_unlock(&upper->lock); } break; case SNIOC_GET_USTATE: { nxrmutex_lock(&upper->lock); memcpy((FAR void *)(uintptr_t)arg, &user->state, sizeof(user->state)); nxrmutex_unlock(&upper->lock); } break; case SNIOC_SET_INTERVAL: { nxrmutex_lock(&upper->lock); ret = sensor_update_interval(filep, upper, user, arg1 ? arg1 : UINT32_MAX); nxrmutex_unlock(&upper->lock); } break; case SNIOC_BATCH: { nxrmutex_lock(&upper->lock); ret = sensor_update_latency(filep, upper, user, arg1); nxrmutex_unlock(&upper->lock); } break; case SNIOC_SELFTEST: { if (lower->ops->selftest == NULL) { ret = -ENOTSUP; break; } ret = lower->ops->selftest(lower, filep, arg); } break; case SNIOC_SET_CALIBVALUE: { if (lower->ops->set_calibvalue == NULL) { ret = -ENOTSUP; break; } ret = lower->ops->set_calibvalue(lower, filep, arg); } break; case SNIOC_CALIBRATE: { if (lower->ops->calibrate == NULL) { ret = -ENOTSUP; break; } ret = lower->ops->calibrate(lower, filep, arg); } break; case SNIOC_SET_USERPRIV: { nxrmutex_lock(&upper->lock); upper->state.priv = (uint64_t)arg; nxrmutex_unlock(&upper->lock); } break; case SNIOC_SET_BUFFER_NUMBER: { nxrmutex_lock(&upper->lock); if (!circbuf_is_init(&upper->buffer)) { if (arg1 >= lower->nbuffer) { lower->nbuffer = arg1; upper->state.nbuffer = arg1; } else { ret = -ERANGE; } } else { ret = -EBUSY; } nxrmutex_unlock(&upper->lock); } break; case SNIOC_UPDATED: { nxrmutex_lock(&upper->lock); *(FAR bool *)(uintptr_t)arg = sensor_is_updated(upper, user); nxrmutex_unlock(&upper->lock); } break; case SNIOC_GET_INFO: { if (lower->ops->get_info == NULL) { ret = -ENOTSUP; break; } ret = lower->ops->get_info(lower, filep, (FAR struct sensor_device_info_s *)(uintptr_t)arg); } break; case SNIOC_GET_EVENTS: { nxrmutex_lock(&upper->lock); *(FAR unsigned int *)(uintptr_t)arg = user->event; user->event = 0; user->changed = false; nxrmutex_unlock(&upper->lock); } break; case SNIOC_FLUSH: { nxrmutex_lock(&upper->lock); /* If the sensor is not activated, return -EINVAL. */ if (upper->state.nsubscribers == 0) { nxrmutex_unlock(&upper->lock); return -EINVAL; } if (lower->ops->flush != NULL) { /* Lower half driver will do flush in asynchronous mode, * flush will be completed until push event happened with * bytes is zero. */ ret = lower->ops->flush(lower, filep); if (ret >= 0) { user->flushing = true; } } else { /* If flush is not supported, complete immediately */ user->event |= SENSOR_EVENT_FLUSH_COMPLETE; sensor_pollnotify_one(user, POLLPRI, user->role); } nxrmutex_unlock(&upper->lock); } break; default: /* Lowerhalf driver process other cmd. */ if (lower->ops->control) { ret = lower->ops->control(lower, filep, cmd, arg); } else { ret = -ENOTTY; } break; } return ret; } static int sensor_poll(FAR struct file *filep, FAR struct pollfd *fds, bool setup) { FAR struct inode *inode = filep->f_inode; FAR struct sensor_upperhalf_s *upper = inode->i_private; FAR struct sensor_lowerhalf_s *lower = upper->lower; FAR struct sensor_user_s *user = filep->f_priv; pollevent_t eventset = 0; int semcount; int ret = 0; nxrmutex_lock(&upper->lock); if (setup) { /* Don't have enough space to store fds */ if (user->fds) { ret = -ENOSPC; goto errout; } user->fds = fds; fds->priv = filep; if (lower->ops->fetch) { /* Always return POLLIN for fetch data directly(non-block) */ if (filep->f_oflags & O_NONBLOCK) { eventset |= POLLIN; } else { nxsem_get_value(&user->buffersem, &semcount); if (semcount > 0) { eventset |= POLLIN; } } } else if (sensor_is_updated(upper, user)) { eventset |= POLLIN; } if (user->changed) { eventset |= POLLPRI; } poll_notify(&fds, 1, eventset); } else { user->fds = NULL; fds->priv = NULL; } errout: nxrmutex_unlock(&upper->lock); return ret; } static ssize_t sensor_push_event(FAR void *priv, FAR const void *data, size_t bytes) { FAR struct sensor_upperhalf_s *upper = priv; FAR struct sensor_lowerhalf_s *lower = upper->lower; FAR struct sensor_user_s *user; unsigned long envcount; int semcount; int ret; nxrmutex_lock(&upper->lock); if (bytes == 0) { list_for_every_entry(&upper->userlist, user, struct sensor_user_s, node) { if (user->flushing) { user->flushing = false; user->event |= SENSOR_EVENT_FLUSH_COMPLETE; sensor_pollnotify_one(user, POLLPRI, user->role); } } nxrmutex_unlock(&upper->lock); return 0; } envcount = bytes / upper->state.esize; if (bytes != envcount * upper->state.esize) { nxrmutex_unlock(&upper->lock); return -EINVAL; } if (!circbuf_is_init(&upper->buffer)) { /* Initialize sensor buffer when data is first generated */ ret = circbuf_init(&upper->buffer, NULL, lower->nbuffer * upper->state.esize); if (ret < 0) { nxrmutex_unlock(&upper->lock); return ret; } ret = circbuf_init(&upper->timing, NULL, lower->nbuffer * TIMING_BUF_ESIZE); if (ret < 0) { circbuf_uninit(&upper->buffer); nxrmutex_unlock(&upper->lock); return ret; } } circbuf_overwrite(&upper->buffer, data, bytes); sensor_generate_timing(upper, envcount); list_for_every_entry(&upper->userlist, user, struct sensor_user_s, node) { if (sensor_is_updated(upper, user)) { nxsem_get_value(&user->buffersem, &semcount); if (semcount < 1) { nxsem_post(&user->buffersem); } sensor_pollnotify_one(user, POLLIN, SENSOR_ROLE_RD); } } nxrmutex_unlock(&upper->lock); return bytes; } static void sensor_notify_event(FAR void *priv) { FAR struct sensor_upperhalf_s *upper = priv; FAR struct sensor_user_s *user; int semcount; nxrmutex_lock(&upper->lock); list_for_every_entry(&upper->userlist, user, struct sensor_user_s, node) { nxsem_get_value(&user->buffersem, &semcount); if (semcount < 1) { nxsem_post(&user->buffersem); } sensor_pollnotify_one(user, POLLIN, SENSOR_ROLE_RD); } nxrmutex_unlock(&upper->lock); } /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** * Name: sensor_remap_vector_raw16 * * Description: * This function remap the sensor data according to the place position on * board. The value of place is determined base on g_remap_tbl. * * Input Parameters: * in - A pointer to input data need remap. * out - A pointer to output data. * place - The place position of sensor on board, * ex:SENSOR_BODY_COORDINATE_PX * ****************************************************************************/ void sensor_remap_vector_raw16(FAR const int16_t *in, FAR int16_t *out, int place) { FAR const struct sensor_axis_map_s *remap; int16_t tmp[3]; DEBUGASSERT(place < (sizeof(g_remap_tbl) / sizeof(g_remap_tbl[0]))); remap = &g_remap_tbl[place]; tmp[0] = in[remap->src_x] * remap->sign_x; tmp[1] = in[remap->src_y] * remap->sign_y; tmp[2] = in[remap->src_z] * remap->sign_z; memcpy(out, tmp, sizeof(tmp)); } /**************************************************************************** * Name: sensor_register * * Description: * This function binds an instance of a "lower half" Sensor driver with the * "upper half" Sensor device and registers that device so that can be used * by application code. * * We will register the chararter device by node name format based on the * type of sensor. Multiple types of the same type are distinguished by * numbers. eg: accel0, accel1 * * Input Parameters: * dev - A pointer to an instance of lower half sensor driver. This * instance is bound to the sensor driver and must persists as long * as the driver persists. * devno - The user specifies which device of this type, from 0. If the * devno alerady exists, -EEXIST will be returned. * * Returned Value: * OK if the driver was successfully register; A negated errno value is * returned on any failure. * ****************************************************************************/ int sensor_register(FAR struct sensor_lowerhalf_s *lower, int devno) { FAR char *path; int ret; DEBUGASSERT(lower != NULL); path = lib_get_pathbuffer(); if (path == NULL) { return -ENOMEM; } snprintf(path, PATH_MAX, DEVNAME_FMT, g_sensor_meta[lower->type].name, lower->uncalibrated ? DEVNAME_UNCAL : "", devno); ret = sensor_custom_register(lower, path, g_sensor_meta[lower->type].esize); lib_put_pathbuffer(path); return ret; } /**************************************************************************** * Name: sensor_custom_register * * Description: * This function binds an instance of a "lower half" Sensor driver with the * "upper half" Sensor device and registers that device so that can be used * by application code. * * You can register the character device type by specific path and esize. * This API corresponds to the sensor_custom_unregister. * * Input Parameters: * dev - A pointer to an instance of lower half sensor driver. This * instance is bound to the sensor driver and must persists as long * as the driver persists. * path - The user specifies path of device. ex: /dev/uorb/xxx. * esize - The element size of intermediate circular buffer. * * Returned Value: * OK if the driver was successfully register; A negated errno value is * returned on any failure. * ****************************************************************************/ int sensor_custom_register(FAR struct sensor_lowerhalf_s *lower, FAR const char *path, size_t esize) { FAR struct sensor_upperhalf_s *upper; int ret = -EINVAL; DEBUGASSERT(lower != NULL); if (lower->type >= SENSOR_TYPE_COUNT || !esize) { snerr("ERROR: type is invalid\n"); return ret; } /* Allocate the upper-half data structure */ upper = kmm_zalloc(sizeof(struct sensor_upperhalf_s)); if (!upper) { snerr("ERROR: Allocation failed\n"); return -ENOMEM; } /* Initialize the upper-half data structure */ list_initialize(&upper->userlist); upper->state.esize = esize; upper->state.min_interval = UINT32_MAX; if (lower->ops->activate) { upper->state.nadvertisers = 1; } nxrmutex_init(&upper->lock); /* Bind the lower half data structure member */ lower->priv = upper; lower->sensor_lock = sensor_lock; lower->sensor_unlock = sensor_unlock; if (!lower->ops->fetch) { if (!lower->nbuffer) { lower->nbuffer = 1; } lower->push_event = sensor_push_event; } else { lower->notify_event = sensor_notify_event; lower->nbuffer = 0; } #ifdef CONFIG_SENSORS_RPMSG lower = sensor_rpmsg_register(lower, path); if (lower == NULL) { ret = -EIO; goto rpmsg_err; } #endif upper->state.nbuffer = lower->nbuffer; upper->lower = lower; sninfo("Registering %s\n", path); ret = register_driver(path, &g_sensor_fops, 0666, upper); if (ret) { goto drv_err; } return ret; drv_err: #ifdef CONFIG_SENSORS_RPMSG sensor_rpmsg_unregister(lower); rpmsg_err: #endif nxrmutex_destroy(&upper->lock); kmm_free(upper); return ret; } /**************************************************************************** * Name: sensor_unregister * * Description: * This function unregister character node and release all resource about * upper half driver. * * Input Parameters: * dev - A pointer to an instance of lower half sensor driver. This * instance is bound to the sensor driver and must persists as long * as the driver persists. * devno - The user specifies which device of this type, from 0. ****************************************************************************/ void sensor_unregister(FAR struct sensor_lowerhalf_s *lower, int devno) { FAR char *path; path = lib_get_pathbuffer(); if (path == NULL) { return; } snprintf(path, PATH_MAX, DEVNAME_FMT, g_sensor_meta[lower->type].name, lower->uncalibrated ? DEVNAME_UNCAL : "", devno); sensor_custom_unregister(lower, path); lib_put_pathbuffer(path); } /**************************************************************************** * Name: sensor_custom_unregister * * Description: * This function unregister character node and release all resource about * upper half driver. This API corresponds to the sensor_custom_register. * * Input Parameters: * dev - A pointer to an instance of lower half sensor driver. This * instance is bound to the sensor driver and must persists as long * as the driver persists. * path - The user specifies path of device, ex: /dev/uorb/xxx ****************************************************************************/ void sensor_custom_unregister(FAR struct sensor_lowerhalf_s *lower, FAR const char *path) { FAR struct sensor_upperhalf_s *upper; DEBUGASSERT(lower != NULL); DEBUGASSERT(lower->priv != NULL); upper = lower->priv; sninfo("UnRegistering %s\n", path); unregister_driver(path); #ifdef CONFIG_SENSORS_RPMSG sensor_rpmsg_unregister(lower); #endif nxrmutex_destroy(&upper->lock); if (circbuf_is_init(&upper->buffer)) { circbuf_uninit(&upper->buffer); circbuf_uninit(&upper->timing); } kmm_free(upper); }
07-11
依然不能准确的找到最低点高于z0的实体我把完整的代码发你检查下,现在只解决(block == gtbody)这部分的问题,仔细检查问题,//============================================================================== // WARNING!! This file is overwritten by the Block Styler while generating // the automation code. Any modifications to this file will be lost after // generating the code again. // // Filename: D:\NXopen\BaiduSyncdisk\Application\gaiyansetool.hpp // // This file was generated by the NX Block Styler // Created by: MICH-ROG // Version: NX 12 // Date: 07-31-2025 (Format: mm-dd-yyyy) // Time: 16:55 // //============================================================================== #ifndef GAIYANSETOOL_H_INCLUDED #define GAIYANSETOOL_H_INCLUDED //------------------------------------------------------------------------------ //These includes are needed for the following template code //------------------------------------------------------------------------------ #include <uf_defs.h> #include <uf_ui_types.h> #include <iostream> #include <NXOpen/Session.hxx> #include <NXOpen/UI.hxx> #include <NXOpen/NXMessageBox.hxx> #include <NXOpen/Callback.hxx> #include <NXOpen/NXException.hxx> #include <NXOpen/BlockStyler_UIBlock.hxx> #include <NXOpen/BlockStyler_BlockDialog.hxx> #include <NXOpen/BlockStyler_PropertyList.hxx> #include <NXOpen/BlockStyler_Group.hxx> #include <NXOpen/BlockStyler_Enumeration.hxx> #include <NXOpen/BlockStyler_FaceCollector.hxx> #include <NXOpen/BlockStyler_ObjectColorPicker.hxx> #include <NXOpen/BlockStyler_Button.hxx> #include "uf_all.h" #include "HuNXOpen.h" #include <algorithm> // 包含std::sort算法 #include <set> // 包含std::set容器 #include <vector> // 包含std::vector容器 #include <cmath> // 包含数学函数 #include <limits> // 包含数值极限 #include <memory> // 包含智能指针 #include <NXOpen/Part.hxx> #include <NXOpen/Body.hxx> #include <NXOpen/Face.hxx> #include <NXOpen/Point.hxx> #include <NXOpen/Direction.hxx> #include <NXOpen/Unit.hxx> #include <vector> #include <cmath> #include <uf_part.h> #include <cfloat> #include <uf_eval.h> //------------------------------------------------------------------------------ // Namespaces needed for following template //------------------------------------------------------------------------------ using namespace std; using namespace NXOpen; using namespace NXOpen::BlockStyler; class DllExport gaiyansetool { // class members public: static Session *theSession; static UI *theUI; gaiyansetool(); ~gaiyansetool(); int Show(); //----------------------- BlockStyler Callback Prototypes --------------------- // The following member function prototypes define the callbacks // specified in your BlockStyler dialog. The empty implementation // of these prototypes is provided in the gaiyansetool.cpp file. // You are REQUIRED to write the implementation for these functions. //------------------------------------------------------------------------------ void initialize_cb(); void dialogShown_cb(); int apply_cb(); int ok_cb(); int update_cb(NXOpen::BlockStyler::UIBlock* block); PropertyList* GetBlockProperties(const char *blockID); private: const char* theDlxFileName; NXOpen::BlockStyler::BlockDialog* theDialog; NXOpen::BlockStyler::Group* group1;// Block type: Group NXOpen::BlockStyler::Enumeration* enum0;// Block type: Enumeration NXOpen::BlockStyler::Group* group0;// Block type: Group NXOpen::BlockStyler::FaceCollector* face1;// Block type: Face Collector NXOpen::BlockStyler::Group* group;// Block type: Group NXOpen::BlockStyler::ObjectColorPicker* color1;// Block type: Color Picker NXOpen::BlockStyler::ObjectColorPicker* color2;// Block type: Color Picker NXOpen::BlockStyler::ObjectColorPicker* color3;// Block type: Color Picker NXOpen::BlockStyler::ObjectColorPicker* color4;// Block type: Color Picker NXOpen::BlockStyler::Button* bu1;// Block type: Button NXOpen::BlockStyler::Button* bu2;// Block type: Button NXOpen::BlockStyler::Button* bu3;// Block type: Button NXOpen::BlockStyler::Button* bu4;// Block type: Button NXOpen::BlockStyler::ObjectColorPicker* color5;// Block type: Color Picker NXOpen::BlockStyler::ObjectColorPicker* color6;// Block type: Color Picker NXOpen::BlockStyler::ObjectColorPicker* color7;// Block type: Color Picker NXOpen::BlockStyler::ObjectColorPicker* color8;// Block type: Color Picker NXOpen::BlockStyler::Button* bu5;// Block type: Button NXOpen::BlockStyler::Button* bu6;// Block type: Button NXOpen::BlockStyler::Button* bu7;// Block type: Button NXOpen::BlockStyler::Button* bu8;// Block type: Button NXOpen::BlockStyler::ObjectColorPicker* color9;// Block type: Color Picker NXOpen::BlockStyler::ObjectColorPicker* color10;// Block type: Color Picker NXOpen::BlockStyler::ObjectColorPicker* color11;// Block type: Color Picker NXOpen::BlockStyler::ObjectColorPicker* color12;// Block type: Color Picker NXOpen::BlockStyler::Button* bu9;// Block type: Button NXOpen::BlockStyler::Button* bu10;// Block type: Button NXOpen::BlockStyler::Button* bu11;// Block type: Button NXOpen::BlockStyler::Button* bu12;// Block type: Button NXOpen::BlockStyler::Group* group2;// Block type: Group NXOpen::BlockStyler::Button* dbpface;// Block type: Button NXOpen::BlockStyler::Button* gtbody;// Block type: Button NXOpen::BlockStyler::Button* arcface;// Block type: Button NXOpen::BlockStyler::Button* gaodipoints;// Block type: Button NXOpen::BlockStyler::Button* Keyway1;// Block type: Button }; #endif //GAIYANSETOOL_H_INCLUDED 以上是头文件,以下是源文件,//============================================================================== // WARNING!! This file is overwritten by the Block UI Styler while generating // the automation code. Any modifications to this file will be lost after // generating the code again. // // Filename: D:\NXopen\BaiduSyncdisk\Application\gaiyansetool.cpp // // This file was generated by the NX Block UI Styler // Created by: MICH-ROG // Version: NX 12 // Date: 07-31-2025 (Format: mm-dd-yyyy) // Time: 16:55 (Format: hh-mm) // //============================================================================== //============================================================================== // Purpose: This TEMPLATE file contains C++ source to guide you in the // construction of your Block application dialog. The generation of your // dialog file (.dlx extension) is the first step towards dialog construction // within NX. You must now create a NX Open application that // utilizes this file (.dlx). // // The information in this file provides you with the following: // // 1. Help on how to load and display your Block UI Styler dialog in NX // using APIs provided in NXOpen.BlockStyler namespace // 2. The empty callback methods (stubs) associated with your dialog items // have also been placed in this file. These empty methods have been // created simply to start you along with your coding requirements. // The method name, argument list and possible return values have already // been provided for you. //============================================================================== //------------------------------------------------------------------------------ //These includes are needed for the following template code //------------------------------------------------------------------------------ #include "gaiyansetool.hpp" using namespace NXOpen; using namespace NXOpen::BlockStyler; // 辅助结构体存储面信息 struct FaceInfo { TaggedObject* faceObj; double centerZ; int faceType; double radius; }; //------------------------------------------------------------------------------ // Initialize static variables //------------------------------------------------------------------------------ Session *(gaiyansetool::theSession) = NULL; UI *(gaiyansetool::theUI) = NULL; //------------------------------------------------------------------------------ // Constructor for NX Styler class //------------------------------------------------------------------------------ gaiyansetool::gaiyansetool() { try { // Initialize the NX Open C++ API environment gaiyansetool::theSession = NXOpen::Session::GetSession(); gaiyansetool::theUI = UI::GetUI(); theDlxFileName = "gaiyansetool.dlx"; theDialog = gaiyansetool::theUI->CreateDialog(theDlxFileName); // Registration of callback functions theDialog->AddApplyHandler(make_callback(this, &gaiyansetool::apply_cb)); theDialog->AddOkHandler(make_callback(this, &gaiyansetool::ok_cb)); theDialog->AddUpdateHandler(make_callback(this, &gaiyansetool::update_cb)); theDialog->AddInitializeHandler(make_callback(this, &gaiyansetool::initialize_cb)); theDialog->AddDialogShownHandler(make_callback(this, &gaiyansetool::dialogShown_cb)); } catch(exception& ex) { //---- Enter your exception handling code here ----- throw; } } //------------------------------------------------------------------------------ // Destructor for NX Styler class //------------------------------------------------------------------------------ gaiyansetool::~gaiyansetool() { if (theDialog != NULL) { delete theDialog; theDialog = NULL; } } //------------------------------- DIALOG LAUNCHING --------------------------------- // // Before invoking this application one needs to open any part/empty part in NX // because of the behavior of the blocks. // // Make sure the dlx file is in one of the following locations: // 1.) From where NX session is launched // 2.) $UGII_USER_DIR/application // 3.) For released applications, using UGII_CUSTOM_DIRECTORY_FILE is highly // recommended. This variable is set to a full directory path to a file // containing a list of root directories for all custom applications. // e.g., UGII_CUSTOM_DIRECTORY_FILE=$UGII_BASE_DIR\ugii\menus\custom_dirs.dat // // You can create the dialog using one of the following way: // // 1. USER EXIT // // 1) Create the Shared Library -- Refer "Block UI Styler programmer's guide" // 2) Invoke the Shared Library through File->Execute->NX Open menu. // //------------------------------------------------------------------------------ extern "C" DllExport void ufusr(char *param, int *retcod, int param_len) { gaiyansetool *thegaiyansetool = NULL; try { UF_initialize(); //开发的许可函数,初始化 thegaiyansetool = new gaiyansetool(); // The following method shows the dialog immediately thegaiyansetool->Show(); } catch(exception& ex) { //---- Enter your exception handling code here ----- gaiyansetool::theUI->NXMessageBox()->Show("Block Styler", NXOpen::NXMessageBox::DialogTypeError, ex.what()); } if(thegaiyansetool != NULL) { delete thegaiyansetool; thegaiyansetool = NULL; }UF_terminate(); //释放许可函数,结束化 } //------------------------------------------------------------------------------ // This method specifies how a shared image is unloaded from memory // within NX. This method gives you the capability to unload an // internal NX Open application or user exit from NX. Specify any // one of the three constants as a return value to determine the type // of unload to perform: // // // Immediately : unload the library as soon as the automation program has completed // Explicitly : unload the library from the "Unload Shared Image" dialog // AtTermination : unload the library when the NX session terminates // // // NOTE: A program which associates NX Open applications with the menubar // MUST NOT use this option since it will UNLOAD your NX Open application image // from the menubar. //------------------------------------------------------------------------------ extern "C" DllExport int ufusr_ask_unload() { //return (int)Session::LibraryUnloadOptionExplicitly; return (int)Session::LibraryUnloadOptionImmediately; //return (int)Session::LibraryUnloadOptionAtTermination; } //------------------------------------------------------------------------------ // Following method cleanup any housekeeping chores that may be needed. // This method is automatically called by NX. //------------------------------------------------------------------------------ extern "C" DllExport void ufusr_cleanup(void) { try { //---- Enter your callback code here ----- } catch(exception& ex) { //---- Enter your exception handling code here ----- gaiyansetool::theUI->NXMessageBox()->Show("Block Styler", NXOpen::NXMessageBox::DialogTypeError, ex.what()); } } int gaiyansetool::Show() { try { theDialog->Show(); } catch(exception& ex) { //---- Enter your exception handling code here ----- gaiyansetool::theUI->NXMessageBox()->Show("Block Styler", NXOpen::NXMessageBox::DialogTypeError, ex.what()); } return 0; } //------------------------------------------------------------------------------ //---------------------Block UI Styler Callback Functions-------------------------- //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ //Callback Name: initialize_cb //------------------------------------------------------------------------------ void gaiyansetool::initialize_cb() { try { group1 = dynamic_cast<NXOpen::BlockStyler::Group*>(theDialog->TopBlock()->FindBlock("group1")); enum0 = dynamic_cast<NXOpen::BlockStyler::Enumeration*>(theDialog->TopBlock()->FindBlock("enum0")); group0 = dynamic_cast<NXOpen::BlockStyler::Group*>(theDialog->TopBlock()->FindBlock("group0")); face1 = dynamic_cast<NXOpen::BlockStyler::FaceCollector*>(theDialog->TopBlock()->FindBlock("face1")); group = dynamic_cast<NXOpen::BlockStyler::Group*>(theDialog->TopBlock()->FindBlock("group")); color1 = dynamic_cast<NXOpen::BlockStyler::ObjectColorPicker*>(theDialog->TopBlock()->FindBlock("color1")); color2 = dynamic_cast<NXOpen::BlockStyler::ObjectColorPicker*>(theDialog->TopBlock()->FindBlock("color2")); color3 = dynamic_cast<NXOpen::BlockStyler::ObjectColorPicker*>(theDialog->TopBlock()->FindBlock("color3")); color4 = dynamic_cast<NXOpen::BlockStyler::ObjectColorPicker*>(theDialog->TopBlock()->FindBlock("color4")); bu1 = dynamic_cast<NXOpen::BlockStyler::Button*>(theDialog->TopBlock()->FindBlock("bu1")); bu2 = dynamic_cast<NXOpen::BlockStyler::Button*>(theDialog->TopBlock()->FindBlock("bu2")); bu3 = dynamic_cast<NXOpen::BlockStyler::Button*>(theDialog->TopBlock()->FindBlock("bu3")); bu4 = dynamic_cast<NXOpen::BlockStyler::Button*>(theDialog->TopBlock()->FindBlock("bu4")); color5 = dynamic_cast<NXOpen::BlockStyler::ObjectColorPicker*>(theDialog->TopBlock()->FindBlock("color5")); color6 = dynamic_cast<NXOpen::BlockStyler::ObjectColorPicker*>(theDialog->TopBlock()->FindBlock("color6")); color7 = dynamic_cast<NXOpen::BlockStyler::ObjectColorPicker*>(theDialog->TopBlock()->FindBlock("color7")); color8 = dynamic_cast<NXOpen::BlockStyler::ObjectColorPicker*>(theDialog->TopBlock()->FindBlock("color8")); bu5 = dynamic_cast<NXOpen::BlockStyler::Button*>(theDialog->TopBlock()->FindBlock("bu5")); bu6 = dynamic_cast<NXOpen::BlockStyler::Button*>(theDialog->TopBlock()->FindBlock("bu6")); bu7 = dynamic_cast<NXOpen::BlockStyler::Button*>(theDialog->TopBlock()->FindBlock("bu7")); bu8 = dynamic_cast<NXOpen::BlockStyler::Button*>(theDialog->TopBlock()->FindBlock("bu8")); color9 = dynamic_cast<NXOpen::BlockStyler::ObjectColorPicker*>(theDialog->TopBlock()->FindBlock("color9")); color10 = dynamic_cast<NXOpen::BlockStyler::ObjectColorPicker*>(theDialog->TopBlock()->FindBlock("color10")); color11 = dynamic_cast<NXOpen::BlockStyler::ObjectColorPicker*>(theDialog->TopBlock()->FindBlock("color11")); color12 = dynamic_cast<NXOpen::BlockStyler::ObjectColorPicker*>(theDialog->TopBlock()->FindBlock("color12")); bu9 = dynamic_cast<NXOpen::BlockStyler::Button*>(theDialog->TopBlock()->FindBlock("bu9")); bu10 = dynamic_cast<NXOpen::BlockStyler::Button*>(theDialog->TopBlock()->FindBlock("bu10")); bu11 = dynamic_cast<NXOpen::BlockStyler::Button*>(theDialog->TopBlock()->FindBlock("bu11")); bu12 = dynamic_cast<NXOpen::BlockStyler::Button*>(theDialog->TopBlock()->FindBlock("bu12")); group2 = dynamic_cast<NXOpen::BlockStyler::Group*>(theDialog->TopBlock()->FindBlock("group2")); dbpface = dynamic_cast<NXOpen::BlockStyler::Button*>(theDialog->TopBlock()->FindBlock("dbpface")); gtbody = dynamic_cast<NXOpen::BlockStyler::Button*>(theDialog->TopBlock()->FindBlock("gtbody")); arcface = dynamic_cast<NXOpen::BlockStyler::Button*>(theDialog->TopBlock()->FindBlock("arcface")); gaodipoints = dynamic_cast<NXOpen::BlockStyler::Button*>(theDialog->TopBlock()->FindBlock("gaodipoints")); Keyway1 = dynamic_cast<NXOpen::BlockStyler::Button*>(theDialog->TopBlock()->FindBlock("Keyway1")); } catch(exception& ex) { //---- Enter your exception handling code here ----- gaiyansetool::theUI->NXMessageBox()->Show("Block Styler", NXOpen::NXMessageBox::DialogTypeError, ex.what()); } } //------------------------------------------------------------------------------ //Callback Name: dialogShown_cb //This callback is executed just before the dialog launch. Thus any value set //here will take precedence and dialog will be launched showing that value. //------------------------------------------------------------------------------ void gaiyansetool::dialogShown_cb() { try { //---- Enter your callback code here ----- } catch(exception& ex) { //---- Enter your exception handling code here ----- gaiyansetool::theUI->NXMessageBox()->Show("Block Styler", NXOpen::NXMessageBox::DialogTypeError, ex.what()); } } //------------------------------------------------------------------------------ //Callback Name: apply_cb //------------------------------------------------------------------------------ int gaiyansetool::apply_cb() { int errorCode = 0; try { //---- Enter your callback code here ----- } catch(exception& ex) { //---- Enter your exception handling code here ----- errorCode = 1; gaiyansetool::theUI->NXMessageBox()->Show("Block Styler", NXOpen::NXMessageBox::DialogTypeError, ex.what()); } return errorCode; } //------------------------------------------------------------------------------ //Callback Name: update_cb //------------------------------------------------------------------------------ int gaiyansetool::update_cb(NXOpen::BlockStyler::UIBlock* block) { try { if (block == enum0) { //---------Enter your code here----------- } else if (block == face1) { //---------Enter your code here----------- } else if (block == color1) { //---------Enter your code here----------- } else if (block == color2) { //---------Enter your code here----------- } else if (block == color3) { //---------Enter your code here----------- } else if (block == color4) { //---------Enter your code here----------- } else if (block == bu1) { try { if (color1 != nullptr) { //获取ui枚举索引值 int iType = 0; iType = this->enum0->GetProperties()->GetEnum("Value"); // ⚙️ 1. 获取属性列表 PropertyList* colorProps = color1->GetProperties(); // 🎨 2. 获取颜色值:关键属性名为 "Value",返回整数向量 std::vector<int> colors = colorProps->GetIntegerVector("Value"); int colorID = colors[0]; // 取第一个值为颜色索引 delete colorProps;// 🧹 3. 释放属性列表内存(必须!) //char msg[256];//调试// //sprintf(msg, "%d", iType); //uc1601(msg, 1);// // ====== 以下是应用颜色到面的逻辑 ====== if (face1 != nullptr) { // 获取选中的面 std::vector<NXOpen::TaggedObject*> vFaces = face1->GetSelectedObjects(); if (vFaces.empty()) { theUI->NXMessageBox()->Show("MICH-明:提示", NXMessageBox::DialogTypeError, "未选择面!"); return 0; } if (iType == 0) { // 🖌️ 遍历所有面并设置颜色 for (auto face : vFaces) { tag_t faceTag = face->Tag(); UF_OBJ_set_color(faceTag, colorID); // 应用颜色 UF_DISP_set_highlight(faceTag, 0); //高亮,0=不高亮,1=高亮 } } else { // 模式1:给选中面所在的实体设置颜色 std::set<tag_t> processedBodies;// 用于记录已处理的实体 for (auto face : vFaces) { tag_t faceTag = face->Tag(); tag_t bodyTag = NULL_TAG; // 获取面所属的实体 UF_MODL_ask_face_body(faceTag, &bodyTag); if (bodyTag != NULL_TAG && processedBodies.find(bodyTag) == processedBodies.end()) { // 清除实体上所有面的单独颜色设置(关键修复) uf_list_p_t faceList = NULL; UF_MODL_ask_body_faces(bodyTag, &faceList); int faceCount = 0; UF_MODL_ask_list_count(faceList, &faceCount); for (int i = 0; i < faceCount; i++) { tag_t bodyFaceTag = NULL_TAG; UF_MODL_ask_list_item(faceList, i, &bodyFaceTag); // 重置面颜色继承 UF_OBJ_set_color(bodyFaceTag, colorID); } UF_MODL_delete_list(&faceList); // 设置实体颜色 UF_OBJ_set_color(bodyTag, colorID); UF_DISP_set_highlight(bodyTag, 0); processedBodies.insert(bodyTag); // 添加到已处理集合 } } } // 清空选择并刷新显示 vFaces.clear(); face1->SetSelectedObjects(vFaces); UF_DISP_refresh(); } } else { theUI->NXMessageBox()->Show("MICH-明:错误提示", NXMessageBox::DialogTypeError, "color1未初始化!"); } } catch (exception& ex) { theUI->NXMessageBox()->Show("MICH-明:错误提示", NXMessageBox::DialogTypeError, ex.what()); } } // 这行结束 else if (block == bu2) { //---------Enter your code here----------- } else if (block == bu3) { //---------Enter your code here----------- } else if (block == bu4) { //---------Enter your code here----------- } else if (block == color5) { //---------Enter your code here----------- } else if (block == color6) { //---------Enter your code here----------- } else if (block == color7) { //---------Enter your code here----------- } else if (block == color8) { //---------Enter your code here----------- } else if (block == bu5) { //---------Enter your code here----------- } else if (block == bu6) { //---------Enter your code here----------- } else if (block == bu7) { //---------Enter your code here----------- } else if (block == bu8) { //---------Enter your code here----------- } else if (block == color9) { //---------Enter your code here----------- } else if (block == color10) { //---------Enter your code here----------- } else if (block == color11) { //---------Enter your code here----------- } else if (block == color12) { //---------Enter your code here----------- } else if (block == bu9) { //---------Enter your code here----------- } else if (block == bu10) { //---------Enter your code here----------- } else if (block == bu11) { //---------Enter your code here----------- } else if (block == bu12) { //---------Enter your code here----------- } else if (block == dbpface) { try { // 确保face1控件已初始化 if (face1 != nullptr) { // 1. 获取当前显示部件 tag_t displayPart = UF_PART_ask_display_part(); // 获取当前显示部件的标签 if (displayPart == NULL_TAG) // 检查是否成功获取显示部件 { theUI->NXMessageBox()->Show("MICH-明:错误提示", NXMessageBox::DialogTypeError, "未找到显示部件!"); // 显示错误消息 return 0; // 退出函数 } // 2. 收集所有可见实体 std::vector<tag_t> allObjects; // 存储可见实体的容器 tag_t currentObject = NULL_TAG; // 当前处理的对象标签 // 遍历部件中的所有实体对象 UF_OBJ_cycle_objs_in_part(displayPart, UF_solid_type, &currentObject); // 获取第一个实体对象 while (currentObject != NULL_TAG) // 循环直到没有更多实体 { // 获取对象的显示属性 UF_OBJ_disp_props_t disp_props; // 声明显示属性结构体 if (UF_OBJ_ask_display_properties(currentObject, &disp_props) == 0) // 获取对象的显示属性 { // 检查对象是否显示(未隐藏) if (UF_OBJ_NOT_BLANKED == disp_props.blank_status) // 检查对象是否显示 { // 检查对象所在图层状态 int layer_status = 0; // 存储图层状态 if (UF_LAYER_ask_status(disp_props.layer, &layer_status) == 0) // 获取图层状态 { // 检查图层是否可见(活动图层或参考图层) if ( layer_status == UF_LAYER_WORK_LAYER || // 工作图层(可见可编辑) layer_status == UF_LAYER_ACTIVE_LAYER || // 活动图层(可见可选) layer_status == UF_LAYER_REFERENCE_LAYER) // 参考图层(仅可见) { allObjects.push_back(currentObject); // 将可见实体添加到容器 } } } } // 获取下一个对象 UF_OBJ_cycle_objs_in_part(displayPart, UF_solid_type, &currentObject); // 继续遍历下一个实体 } if (allObjects.empty()) // 检查是否有可见实体 { theUI->NXMessageBox()->Show("MICH-明:提示", NXMessageBox::DialogTypeInformation, "部件中没有可见实体!"); // 显示提示消息 return 0; // 退出函数 } // 3. 收集所有面 std::vector<TaggedObject*> allFaces; for (tag_t objectTag : allObjects) { // 获取对象上的所有面 uf_list_p_t faceList = NULL; if (UF_MODL_ask_body_faces(objectTag, &faceList) != 0) continue; int faceCount = 0; UF_MODL_ask_list_count(faceList, &faceCount); for (int i = 0; i < faceCount; i++) { tag_t faceTag = NULL_TAG; UF_MODL_ask_list_item(faceList, i, &faceTag); // 创建NXOpen::Face对象并添加到列表 NXOpen::Face* face = dynamic_cast<NXOpen::Face*>(NXOpen::NXObjectManager::Get(faceTag)); if (face) allFaces.push_back(face); } // 释放面列表内存 if (faceList) UF_MODL_delete_list(&faceList); } // ================ 使用UF函数过滤水平面 ================ std::vector<TaggedObject*> horizontalFaces; const double tolerance = 0.0175; // 约1度(弧度) const double z_axis[3] = { 0.0, 0.0, 1.0 }; // 绝对Z轴方向 for (auto faceObj : allFaces) { tag_t faceTag = faceObj->Tag(); int faceType = 0; // 获取面类型 if (UF_MODL_ask_face_type(faceTag, &faceType) == 0 && faceType == UF_MODL_PLANAR_FACE) { double direction[3] = { 0.0, 0.0, 0.0 }; double point[3] = { 0.0, 0.0, 0.0 }; double box[6] = { 0.0 }; double rad = 0.0; double rad_data[2] = { 0.0 }; int status = 0; // 获取面数据 if (UF_MODL_ask_face_data(faceTag, &faceType, point, direction, box, &rad, rad_data, &status) == 0) { // 计算法向与Z轴的点积 double dot = z_axis[0] * direction[0] + z_axis[1] * direction[1] + z_axis[2] * direction[2]; // 法向平行于Z轴(点积接近1或-1) if (fabs(fabs(dot) - 1.0) < tolerance) { horizontalFaces.push_back(faceObj); } } } } // ================ 结束过滤代码 ================ // ================ 找出Z方向最高的水平面 ================ std::vector<TaggedObject*> highestFaces; double maxZ = -DBL_MAX; // 初始化为最小可能值 // 1. 找出最高Z值 for (auto faceObj : horizontalFaces) { tag_t faceTag = faceObj->Tag(); double box[6]; // [xmin, ymin, zmin, xmax, ymax, zmax] // 获取面的包围盒 if (UF_MODL_ask_bounding_box(faceTag, box) == 0) { // 使用包围盒的zmax作为面的高度 double zMax = box[5]; // 更新最大Z值 if (zMax > maxZ) { maxZ = zMax; } } } // 2. 收集所有位于最高Z值位置的面 const double zTolerance = 0.001; // Z值容差(1毫米) for (auto faceObj : horizontalFaces) { tag_t faceTag = faceObj->Tag(); double box[6]; if (UF_MODL_ask_bounding_box(faceTag, box) == 0) { double zMax = box[5]; // 检查是否在最高Z值位置(考虑容差) if (fabs(zMax - maxZ) < zTolerance) { highestFaces.push_back(faceObj); } } } // ================ 结束最高面选择 ================ // 4. 设置到FaceCollector控件 - 使用最高水平面 face1->SetSelectedObjects(highestFaces); // 5. 刷新界面 UF_DISP_refresh(); //// 显示成功消息 //char msg[256]; //sprintf(msg, "已选择 %d 个最高水平面 (Z = %.2f)", (int)highestFaces.size(), maxZ); //theUI->NXMessageBox()->Show("操作成功", NXMessageBox::DialogTypeInformation, msg); } else { theUI->NXMessageBox()->Show("MICH-明:提示错误", NXMessageBox::DialogTypeError, "面选择控件未初始化!"); } } catch (exception& ex) { theUI->NXMessageBox()->Show("MICH-明:提示异常错误", NXMessageBox::DialogTypeError, ex.what()); } //---------Enter your code here----------- } else if (block == gtbody) { try { // 1. 获取当前显示部件 tag_t displayPart = UF_PART_ask_display_part(); // 获取当前工作部件 if (displayPart == NULL_TAG) // 检查部件是否有效 { theUI->NXMessageBox()->Show("错误提示", NXMessageBox::DialogTypeError, "未找到显示部件!"); return 0; } // 2. 收集所有可见实体 std::vector<tag_t> allBodies; // 存储所有可见实体 tag_t currentBody = NULL_TAG; UF_OBJ_cycle_objs_in_part(displayPart, UF_solid_type, &currentBody); // 开始遍历实体 while (currentBody != NULL_TAG) // 遍历所有实体 { UF_OBJ_disp_props_t disp_props; if (UF_OBJ_ask_display_properties(currentBody, &disp_props) == 0) // 获取显示属性 { // 仅处理未隐藏实体 if (disp_props.blank_status == UF_OBJ_NOT_BLANKED) // 检查可见性 { int layer_status = 0; UF_LAYER_ask_status(disp_props.layer, &layer_status); // 获取图层状态 // 检查可见图层 if (layer_status == UF_LAYER_WORK_LAYER || layer_status == UF_LAYER_ACTIVE_LAYER || layer_status == UF_LAYER_REFERENCE_LAYER) { allBodies.push_back(currentBody); // 添加到可见实体列表 } } } UF_OBJ_cycle_objs_in_part(displayPart, UF_solid_type, &currentBody); // 获取下一个实体 } if (allBodies.empty()) // 检查是否有可见实体 { theUI->NXMessageBox()->Show("提示", NXMessageBox::DialogTypeInformation, "部件中没有可见实体!"); return 0; } // 3. 收集需要着色的实体 std::set<tag_t> targetBodies; // 使用set避免重复 const double tolerance = 0.0175; // 约1度(弧度)的法向容差 const double z_axis[3] = { 0.0, 0.0, 1.0 }; // Z轴方向向量 const double z_tolerance = 0.001; // Z坐标容差(1毫米) // 遍历所有实体 for (tag_t bodyTag : allBodies) { uf_list_p_t faceList = NULL; if (UF_MODL_ask_body_faces(bodyTag, &faceList) != 0) continue; // 获取实体所有面 int faceCount = 0; UF_MODL_ask_list_count(faceList, &faceCount); // 获取面数量 double minZ = DBL_MAX; // 初始化最小Z值为最大值 tag_t lowestFace = NULL_TAG; // 存储最低水平面 // 遍历实体的每个面 for (int i = 0; i < faceCount; i++) { tag_t faceTag = NULL_TAG; UF_MODL_ask_list_item(faceList, i, &faceTag); // 获取面标签 int faceType = 0; if (UF_MODL_ask_face_type(faceTag, &faceType) != 0) continue; // 获取面类型 // 只处理平面 if (faceType == UF_MODL_PLANAR_FACE) { double direction[3] = { 0 }; // 面法向 double point[3] = { 0 }; // 面上一点 double box[6] = { 0 }; // 面边界框 double rad = 0, rad_data[2] = { 0 }; int status = 0; // 获取面几何数据 if (UF_MODL_ask_face_data(faceTag, &faceType, point, direction, box, &rad, rad_data, &status) == 0) { // 计算法向与Z轴的点积 double dot = z_axis[0] * direction[0] + z_axis[1] * direction[1] + z_axis[2] * direction[2]; // 检查是否为水平面(法向平行Z轴) if (fabs(fabs(dot) - 1.0) < tolerance) { // 获取面的最低点Z坐标(边界框Zmin) double faceMinZ = box[4]; // 更新最低水平面 if (faceMinZ < minZ) { minZ = faceMinZ; lowestFace = faceTag; } } } } } // 检查是否找到最低水平面且高于XY平面 if (lowestFace != NULL_TAG && minZ > z_tolerance) { targetBodies.insert(bodyTag); // 添加到目标实体集合 } UF_MODL_delete_list(&faceList); // 释放面列表内存 } // 4. 检查是否有符合条件的实体 if (targetBodies.empty()) { theUI->NXMessageBox()->Show("提示", NXMessageBox::DialogTypeInformation, "未找到最低水平面高于XY平面的实体!"); return 0; } // 5. 着色处理 if (color5 != nullptr) // 确保颜色控件有效 { try { // 获取选择的颜色 PropertyList* colorProps = color5->GetProperties(); std::vector<int> colors = colorProps->GetIntegerVector("Value"); int colorID = colors[0]; // 提取颜色ID delete colorProps; // 释放属性对象 // 6. 为实体着色(保留面颜色重置) for (tag_t bodyTag : targetBodies) // 遍历目标实体 { // 重置实体所有面的颜色为继承 uf_list_p_t faceList = NULL; if (UF_MODL_ask_body_faces(bodyTag, &faceList) == 0) { int faceCount = 0; UF_MODL_ask_list_count(faceList, &faceCount); for (int i = 0; i < faceCount; i++) { tag_t faceTag = NULL_TAG; UF_MODL_ask_list_item(faceList, i, &faceTag); UF_OBJ_set_color(faceTag, 0); // 0=继承实体颜色 } UF_MODL_delete_list(&faceList); // 释放面列表 } // 设置实体颜色 UF_OBJ_set_color(bodyTag, colorID); UF_DISP_set_highlight(bodyTag, 0); // 取消高亮 } UF_DISP_refresh(); // 刷新显示 // 显示结果信息 char msg[256]; snprintf(msg, sizeof(msg), "已为 %zu 个实体设置颜色", targetBodies.size()); theUI->NXMessageBox()->Show("着色完成", NXMessageBox::DialogTypeInformation, msg); } catch (std::exception& ex) { theUI->NXMessageBox()->Show("着色错误", NXMessageBox::DialogTypeError, ex.what()); } } else { theUI->NXMessageBox()->Show("错误", NXMessageBox::DialogTypeError, "颜色选择控件未初始化!"); } } catch (std::exception& ex) { theUI->NXMessageBox()->Show("系统错误", NXMessageBox::DialogTypeError, ex.what()); } //---------Enter your code here----------- } else if(block == arcface) { try { if (face1 != nullptr) // 确保面选择控件有效 { // 1. 获取当前显示部件 tag_t displayPart = UF_PART_ask_display_part(); // 获取当前显示的部件标签 if (displayPart == NULL_TAG) // 检查是否获取成功 { theUI->NXMessageBox()->Show("MICH-明:错误提示", NXMessageBox::DialogTypeError, "未找到显示部件!"); // 显示错误信息 return 0; // 提前返回 } // 2. 收集可见实体并筛选最低点高于Z0的实体 std::vector<tag_t> filteredObjects; // 存储符合条件的实体标签 tag_t currentObject = NULL_TAG; // 当前遍历的实体 UF_OBJ_cycle_objs_in_part(displayPart, UF_solid_type, &currentObject); // 开始遍历部件中的实体 while (currentObject != NULL_TAG) // 遍历所有实体 { // 检查实体的显示属性 UF_OBJ_disp_props_t disp_props; // 存储显示属性 if (UF_OBJ_ask_display_properties(currentObject, &disp_props) == 0) // 获取显示属性 { // 检查实体是否未被隐藏 if (UF_OBJ_NOT_BLANKED == disp_props.blank_status) // 实体可见 { int layer_status = 0; // 图层状态 if (UF_LAYER_ask_status(disp_props.layer, &layer_status) == 0) // 获取图层状态 { // 检查是否在可见图层上 if (layer_status == UF_LAYER_WORK_LAYER || layer_status == UF_LAYER_ACTIVE_LAYER || layer_status == UF_LAYER_REFERENCE_LAYER) { // 计算实体的边界框 double bbox[6] = { 0 }; // [xmin, ymin, zmin, xmax, ymax, zmax] if (UF_MODL_ask_bounding_box(currentObject, bbox) == 0) // 获取边界框 { // 检查实体最低点是否高于Z0 if (bbox[2] > 0.0) // bbox[2] 是 Zmin { filteredObjects.push_back(currentObject); // 添加到筛选列表 //// 调试信息:显示实体的最低点高度 //char debugMsg[256]; // 调试信息缓冲区 //snprintf(debugMsg, sizeof(debugMsg), // "实体 %d 最低点: %.2f", currentObject, bbox[2]); // 格式化信息 // 使用NXMessageBox替代theUFUI //theUI->NXMessageBox()->Show("调试信息", NXMessageBox::DialogTypeInformation, debugMsg); // 显示调试信息 } } } } } } UF_OBJ_cycle_objs_in_part(displayPart, UF_solid_type, &currentObject); // 获取下一个实体 } //// 显示筛选后的实体数量 //char objCountMsg[256]; // 消息缓冲区 //snprintf(objCountMsg, sizeof(objCountMsg), // "找到最低点高于Z0的实体数量: %zu", filteredObjects.size()); // 格式化消息 //theUI->NXMessageBox()->Show("实体筛选", NXMessageBox::DialogTypeInformation, objCountMsg); // 显示消息 if (filteredObjects.empty()) // 检查是否有符合条件的实体 { theUI->NXMessageBox()->Show("MICH-明:提示", NXMessageBox::DialogTypeInformation, "没有符合条件的实体!"); // 显示提示 return 0; // 提前返回 } // 3. 从筛选后的实体中收集所有圆弧面 std::vector<NXOpen::TaggedObject*> allFaces; // 存储所有面对象 for (tag_t objectTag : filteredObjects) // 遍历筛选后的实体 { uf_list_p_t faceList = nullptr; // 面列表指针 if (UF_MODL_ask_body_faces(objectTag, &faceList) != 0) continue; // 获取实体所有面 // 自动释放列表内存的RAII封装 auto listDeleter = [](uf_list_p_t* list) { if (*list) UF_MODL_delete_list(list); }; // 自定义删除器 std::unique_ptr<uf_list_p_t, decltype(listDeleter)> listGuard(&faceList, listDeleter); // 智能指针管理 int faceCount = 0; // 面数量 UF_MODL_ask_list_count(faceList, &faceCount); // 获取面数量 for (int i = 0; i < faceCount; i++) // 遍历所有面 { tag_t faceTag = NULL_TAG; // 面标签 UF_MODL_ask_list_item(faceList, i, &faceTag); // 获取面标签 if (auto face = dynamic_cast<NXOpen::Face*>(NXOpen::NXObjectManager::Get(faceTag))) // 转换为面对象 { allFaces.push_back(face); // 添加到面列表 } } } // 4. 收集所有圆弧面(包括圆柱、圆锥和圆角面) std::vector<NXOpen::TaggedObject*> allArcFaces; // 存储圆弧面对象 int cylinderCount = 0, coneCount = 0, blendCount = 0; // 各类面计数器 for (auto faceObj : allFaces) // 遍历所有面 { tag_t faceTag = faceObj->Tag(); // 获取面标签 int faceType = 0; // 面类型 double point[3] = { 0 }; // 点坐标 double dir[3] = { 0 }; // 方向向量 double box[6] = { 0 }; // 边界框 double radius = 0; // 半径 double rad_data[2] = { 0 }; // 半径数据 int norm_dir = 0; // 法线方向 // 获取面数据 if (UF_MODL_ask_face_data(faceTag, &faceType, point, dir, box, &radius, rad_data, &norm_dir) != 0) continue; // 跳过获取失败的面 // 只收集圆弧相关面类型 if (faceType == 16) // 圆柱面 { cylinderCount++; // 增加计数器 allArcFaces.push_back(faceObj); // 添加到圆弧面列表 } else if (faceType == 7) // 圆锥面 { coneCount++; // 增加计数器 allArcFaces.push_back(faceObj); // 添加到圆弧面列表 } else if (faceType == 19) // 圆环曲面 { coneCount++; // 增加计数器 allArcFaces.push_back(faceObj); // 添加到圆弧面列表 } else if (faceType == 18) // 球面 { coneCount++; // 增加计数器 allArcFaces.push_back(faceObj); // 添加到圆弧面列表 } else if (faceType == 23) // 圆角面 { blendCount++; // 增加计数器 allArcFaces.push_back(faceObj); // 添加到圆弧面列表 } } //// 显示圆弧面统计信息 //char debugMsg[256]; // 消息缓冲区 //snprintf(debugMsg, sizeof(debugMsg), // "从筛选实体中找到圆弧面总数: %zu\n圆柱面: %d\n圆锥面: %d\n圆角面: %d", // allArcFaces.size(), cylinderCount, coneCount, blendCount); // 格式化消息 //theUI->NXMessageBox()->Show("圆弧面统计", NXMessageBox::DialogTypeInformation, debugMsg); // 显示消息 if (allArcFaces.empty()) // 检查是否有圆弧面 { theUI->NXMessageBox()->Show("MICH-明:提示", NXMessageBox::DialogTypeInformation, "筛选实体中没有圆弧面!"); // 显示提示 return 0; // 提前返回 } // 5. 直接选择所有圆弧面 face1->SetSelectedObjects(allArcFaces); // 设置选中的面 UF_DISP_refresh(); // 刷新显示 //// 显示最终结果 //char msg[256]; // 结果消息缓冲区 //snprintf(msg, sizeof(msg), "已选择 %zu 个圆弧面", allArcFaces.size()); // 格式化消息 //theUI->NXMessageBox()->Show("操作成功", NXMessageBox::DialogTypeInformation, msg); // 显示结果 } } catch (std::exception& ex) // 捕获异常 { theUI->NXMessageBox()->Show("MICH-明:系统错误", NXMessageBox::DialogTypeError, ex.what()); // 显示错误信息 } //---------Enter your code here----------- } else if(block == gaodipoints) { try { // ⚙️ 1. 获取属性列表 PropertyList* colorProps = color11->GetProperties(); // 🎨 2. 获取颜色值:关键属性名为 "Value",返回整数向量 std::vector<int> colors = colorProps->GetIntegerVector("Value"); int colorID = colors[0]; // 取第一个值为颜色索引 delete colorProps;// 🧹 3. 释放属性列表内存(必须!) if (face1 != nullptr) { // 1. 获取显示部件 tag_t displayPart = UF_PART_ask_display_part(); // 获取当前显示部件 if (displayPart == NULL_TAG) // 检查是否获取成功 { theUI->NXMessageBox()->Show("MICH-明:错误提示", NXMessageBox::DialogTypeError, "未找到显示部件!"); return 0; } // 2. 收集可见实体(复用之前代码中的逻辑) std::vector<tag_t> allObjects; tag_t currentObject = NULL_TAG; UF_OBJ_cycle_objs_in_part(displayPart, UF_solid_type, &currentObject); // 遍历部件中的实体 while (currentObject != NULL_TAG) { UF_OBJ_disp_props_t disp_props; if (UF_OBJ_ask_display_properties(currentObject, &disp_props) == 0) // 获取显示属性 { if (UF_OBJ_NOT_BLANKED == disp_props.blank_status) // 检查是否消隐 { int layer_status = 0; if (UF_LAYER_ask_status(disp_props.layer, &layer_status) == 0) // 检查图层状态 { if (layer_status == UF_LAYER_WORK_LAYER || layer_status == UF_LAYER_ACTIVE_LAYER || layer_status == UF_LAYER_REFERENCE_LAYER) // 仅处理工作层和参考层 { allObjects.push_back(currentObject); // 添加到可见实体列表 } } } } UF_OBJ_cycle_objs_in_part(displayPart, UF_solid_type, &currentObject); // 继续遍历 } if (allObjects.empty()) // 检查是否有可见实体 { theUI->NXMessageBox()->Show("MICH-明:提示", NXMessageBox::DialogTypeInformation, "部件中没有可见实体!"); return 0; } // 3. 准备收集最终选中的面和实体 std::vector<TaggedObject*> resultFaces; // 存储符合条件的面 std::set<tag_t> aboveZ0Bodies; // 存储Z>0的实体(复用之前的逻辑) const double tolerance = 0.0175; // 角度容差(约1度) const double coordTol = 1e-3; // 坐标容差(1微米) const double z_axis[3] = { 0.0, 0.0, 1.0 }; // Z轴方向 // 4. 遍历所有可见实体 for (tag_t bodyTag : allObjects) { // 4.1 收集实体上所有水平面 std::vector<std::pair<tag_t, double>> horizontalFaces; // <面tag, 最小Z坐标> uf_list_p_t faceList = nullptr; if (UF_MODL_ask_body_faces(bodyTag, &faceList) != 0) continue; // 获取实体所有面 // 自动释放列表内存 auto listDeleter = [](uf_list_p_t* list) { if (*list) UF_MODL_delete_list(list); }; std::unique_ptr<uf_list_p_t, decltype(listDeleter)> listGuard(&faceList, listDeleter); int faceCount = 0; UF_MODL_ask_list_count(faceList, &faceCount); // 获取面数量 for (int i = 0; i < faceCount; i++) // 遍历每个面 { tag_t faceTag = NULL_TAG; UF_MODL_ask_list_item(faceList, i, &faceTag); // 获取面tag // 检查是否为水平面 int faceType = 0; if (UF_MODL_ask_face_type(faceTag, &faceType) == 0 && faceType == UF_MODL_PLANAR_FACE) // 只处理平面 { double direction[3] = { 0 }; double point[3] = { 0 }; double box[6] = { 0 }; double rad = 0; double rad_data[2] = { 0 }; int status = 0; if (UF_MODL_ask_face_data(faceTag, &faceType, point, direction, box, &rad, rad_data, &status) == 0) // 获取面数据 { double dot = std::fabs(z_axis[0] * direction[0] + z_axis[1] * direction[1] + z_axis[2] * direction[2]); // 计算法向与Z轴夹角 if (std::abs(dot - 1.0) < tolerance) // 检查是否为水平面 { // 获取面的最小Z坐标 double faceBox[6]; if (UF_MODL_ask_bounding_box(faceTag, faceBox) == 0) // 获取面包围盒 { double minZ = faceBox[2]; // 包围盒Z最小值 horizontalFaces.push_back({ faceTag, minZ }); // 存储水平面信息 } } } } } // 4.2 如果没有水平面则跳过该实体 if (horizontalFaces.empty()) continue; // 4.3 找出除底面外的最低水平面(参考面) // 按Z坐标升序排序 std::sort(horizontalFaces.begin(), horizontalFaces.end(), [](const auto& a, const auto& b) { return a.second < b.second; }); // 按Z值排序 // 找出最低水平面(底面)的高度 double bottomZ = horizontalFaces[0].second; // 找出除底面外的最低水平面高度 double referenceZ = bottomZ; // 初始化为底面高度 bool foundReference = false; for (size_t i = 1; i < horizontalFaces.size(); i++) // 从第二个面开始检查 { // 找到第一个高于底面的水平面 if (horizontalFaces[i].second > bottomZ + coordTol) // 使用容差避免浮点误差 { referenceZ = horizontalFaces[i].second; // 设置参考面高度 foundReference = true; // 标记找到参考面 break; } } // 如果所有水平面都在同一高度(只有底面),则跳过该实体 if (!foundReference) continue; // 4.4 收集实体中高于参考面的所有面 for (int i = 0; i < faceCount; i++) // 再次遍历实体所有面 { tag_t faceTag = NULL_TAG; UF_MODL_ask_list_item(faceList, i, &faceTag); // 获取面tag // 获取面的包围盒 double faceBox[6]; if (UF_MODL_ask_bounding_box(faceTag, faceBox) == 0) // 获取面包围盒 { double minZ = faceBox[2]; // 面的最低点Z坐标 // 面的最低点高于参考面(容差范围内) if (minZ > referenceZ - coordTol) // 使用容差避免浮点误差 { if (auto face = dynamic_cast<NXOpen::Face*>(NXOpen::NXObjectManager::Get(faceTag))) // 转换为Face对象 { resultFaces.push_back(face); // 添加到结果列表 } } } } // 4.5 记录Z>0的实体(复用之前的逻辑) double bodyBox[6]; if (UF_MODL_ask_bounding_box(bodyTag, bodyBox) == 0 && bodyBox[2] > 0.0) // 检查实体是否在Z0以上 { aboveZ0Bodies.insert(bodyTag); // 添加到Z>0实体集合 } } // 5. 检查结果并设置选择 if (resultFaces.empty()) // 检查是否有符合条件的面 { theUI->NXMessageBox()->Show("MICH-明:提示", NXMessageBox::DialogTypeInformation, "未找到符合条件的面!"); return 0; } face1->SetSelectedObjects(resultFaces); // 设置选中的面 for (auto face : resultFaces) { tag_t faceTag = face->Tag(); UF_OBJ_set_color(faceTag, colorID); // 应用颜色 UF_DISP_set_highlight(faceTag, 0); //高亮,0=不高亮,1=高亮 } UF_DISP_refresh(); // 刷新显示 // 6. 显示结果信息 char msg[256]; snprintf(msg, sizeof(msg), "已选中 %zu 个符合条件的面", resultFaces.size()); theUI->NXMessageBox()->Show("操作成功", NXMessageBox::DialogTypeInformation, msg); } } catch (std::exception& ex) // 异常处理 { theUI->NXMessageBox()->Show("MICH-明:系统错误", NXMessageBox::DialogTypeError, ex.what()); } //---------Enter your code here----------- } else if(block == Keyway1) { //---------Enter your code here----------- } } catch(exception& ex) { //---- Enter your exception handling code here ----- gaiyansetool::theUI->NXMessageBox()->Show("Block Styler", NXOpen::NXMessageBox::DialogTypeError, ex.what()); } return 0; } //------------------------------------------------------------------------------ //Callback Name: ok_cb //------------------------------------------------------------------------------ int gaiyansetool::ok_cb() { int errorCode = 0; try { errorCode = apply_cb(); } catch(exception& ex) { //---- Enter your exception handling code here ----- errorCode = 1; gaiyansetool::theUI->NXMessageBox()->Show("Block Styler", NXOpen::NXMessageBox::DialogTypeError, ex.what()); } return errorCode; } //------------------------------------------------------------------------------ //Function Name: GetBlockProperties //Description: Returns the propertylist of the specified BlockID //------------------------------------------------------------------------------ PropertyList* gaiyansetool::GetBlockProperties(const char *blockID) { return theDialog->GetBlockProperties(blockID); }
最新发布
08-04
int rtdDhcpServerAddTempBind(struct client_id *cid, int htype, char *haddr, int haddr_len, DHCP_SERVER_IP ipAddr, struct in_addr subnet, char *poolName, struct dhcp_binding *outBd,BOOL fromMlag) { struct dhcp_binding *binding = NULL; struct hash_member *head = NULL; //DHCP_SERVER_POOL poolParam={}; if (haddr == NULL) { return ERR_BAD_PARAM; } PFM_ENSURE_RET_VAL(poolName, ERR_NO_ERROR); //APPL_IF_ERR_RET(rtdDhcpsPoolGet(poolName,&poolParam )); DHCP_SERVER_RTD_LOCK(); /* * Read binding information from entries with the following format: * idtype:id:subnet:htype:haddr:"expire_date":resource_name */ DBG_DHCP_VRF("ADD TEMP BIND"); if (nbind < DHCPS_IP_MAX_NUM && availreslist == NULL) { nbind = DHCPS_IP_MAX_NUM; rtdDhcpServerGarbageCollect(); } /* Create linked list element. */ head = availreslist; if (availreslist != NULL) { availreslist = availreslist->next; head->next = bindlist; bindlist = head; binding = (struct dhcp_binding *)(head->data); binding->bindtype = AUTO_BIND_TYPE; //binding->ip_addr.ip.s_addr = ipAddr.s_addr; //strncpy(binding->ip_addr.vrfName,poolParam.vrfName,DHCP_VRF_NAME_LEN); COPY_DHCP_SERVER_IP(binding->ip_addr,ipAddr); /* flag set to 0 means not used */ binding->flag = FREE_ENTRY; binding->fromMlag=fromMlag; /* read client identifier value */ memcpy(&binding->cid, cid, sizeof(binding->cid)); /* read subnet number of client */ binding->cid.subnet = subnet; strncpy(binding->cid.vrfName,ipAddr.vrfName,DHCP_VRF_NAME_LEN); /* read hardware address type (e.g. "1" for 10 MB ethernet). */ binding->haddr.htype = htype; /* read client hardware address */ binding->haddr.hlen = haddr_len; memcpy(binding->haddr.haddr, haddr, haddr_len); /* read expiration time for lease */ binding->expire_epoch = 0; /* read expiration time for lease */ binding->temp_epoch = 0; /* if(dhcpsMsgIn.isRxUpMlag) { binding->fromMlag=TRUE; } else { binding->fromMlag=FALSE; } */ if (poolName) { snprintf(binding->poolName, DHCPS_POOLNAME_LEN + 1, "%s", poolName); } hash_del(&cidhashtable, binding->cid.id, binding->cid.idlen, bindcidcmp_not_manual, &binding->cid, free_bind); if ((hash_ins(&cidhashtable, binding->cid.id, binding->cid.idlen, bindcidcmp_not_manual, &binding->cid, binding) < 0)) { head = bindlist; if (bindlist) { bindlist = bindlist->next; } if (head) { head->next = availreslist; } availreslist = head; DHCP_SERVER_RTD_UNLOCK(); return ERR_BAD_PARAM; } hash_del(&iphashtable, (char *)&binding->ip_addr.ip.s_addr, sizeof(UINT32), resipcmp_not_manual, &binding->ip_addr, free_element); if (hash_ins(&iphashtable, (char *)&binding->ip_addr.ip.s_addr, sizeof(UINT32), resipcmp_not_manual, &binding->ip_addr, binding) < 0) { hash_del(&cidhashtable, binding->cid.id, binding->cid.idlen, resipcmp_not_manual, &binding->cid, free_bind); head = bindlist; if (bindlist) { bindlist = bindlist->next; } if (head) { head->next = availreslist; } availreslist = head; DHCP_SERVER_RTD_UNLOCK(); return ERR_BAD_PARAM; } //add_reslist_node(binding); } DBG_DHCP_MLAG("add a temp entry."); _printBinding(*binding); DBG_DHCP_VRF("add client identifier to hash table ok."); if (binding) { _turnoff_bind(binding, TEMP_ENTRY); if (outBd) { memcpy(outBd, binding, sizeof(struct dhcp_binding)); } } else/* binding 为空,添加临时绑定失败 */ { DHCP_SERVER_RTD_UNLOCK(); return ERR_DHCP_SERVER_ADD_TEMP_BIND; } DHCP_SERVER_RTD_UNLOCK(); return ERR_NO_ERROR; } 分析以上代码
07-03
#include "user.h" // 生成唯一ID函数 static int generate_product_id() { static int counter = 1000; return ++counter; } /* 新增农产品 */ Product* operator_add_product(Product* head) { Product* new_node = (Product*)malloc(sizeof(Product)); if (!new_node) { printf("内存分配失败!\n"); return head; } printf("请输入产品ID: "); scanf("%d", &new_node->id); getchar(); // 清空输入缓冲区 printf("请输入产品名称: "); fgets(new_node->name, 30, stdin); new_node->name[strcspn(new_node->name, "\n")] = '\0'; // 去除换行符 printf("请输入产品类型: "); fgets(new_node->type, 20, stdin); new_node->type[strcspn(new_node->type, "\n")] = '\0'; printf("请输入价格: "); scanf("%f", &new_node->price); printf("请输入库存数量: "); scanf("%d", &new_node->stock_quantity); getchar(); printf("请输入产品描述: "); fgets(new_node->description, 100, stdin); new_node->description[strcspn(new_node->description, "\n")] = '\0'; new_node->next = head; return new_node; }//添加农产品 Product* operator_delete_product(Product* head, int target_id) { Product *current = head, *prev = NULL; while (current) { if (current->id == target_id) { if (prev) { prev->next = current->next; } else { head = current->next; } free(current); printf("成功删除ID为%d的产品\n", target_id); return head; } prev = current; current = current->next; } printf("未找到ID为%d的产品\n", target_id); return head; }//删除农产品 void operator_search_product(Product* head, int target_id) { Product* current = head; while (current) { if (current->id == target_id) { printf("\n=== 产品详情 ===\n"); printf("ID: %d\n", current->id); printf("名称: %s\n", current->name); printf("类型: %s\n", current->type); printf("价格: %.2f\n", current->price); printf("库存: %d\n", current->stock_quantity); printf("描述: %s\n", current->description); return; } current = current->next; } printf("未找到ID为%d的产品\n", target_id); }//查询农产品 void operator_modify_product(Product* head, int target_id) { Product* current = head; while (current) { if (current->id == target_id) { printf("请输入新的产品名称: "); fgets(current->name, 30, stdin); current->name[strcspn(current->name, "\n")] = '\0'; printf("请输入新的产品类型: "); fgets(current->type, 20, stdin); current->type[strcspn(current->type, "\n")] = '\0'; printf("请输入新的价格: "); scanf("%f", &current->price); printf("请输入新的库存数量: "); scanf("%d", &current->stock_quantity); getchar(); printf("请输入新的产品描述: "); fgets(current->description, 100, stdin); current->description[strcspn(current->description, "\n")] = '\0'; printf("产品信息更新成功!\n"); return; } current = current->next; } printf("未找到ID为%d的产品\n", target_id); }//修改农产品 void operator_statistics(Product* head) { float total_value = 0; int total_quantity = 0; Product* current = head; while (current) { total_quantity += current->stock_quantity; total_value += current->stock_quantity * current->price; current = current->next; } printf("\n=== 统计结果 ===\n"); printf("总库存数量: %d\n", total_quantity); printf("总库存价值: %.2f\n", total_value); }//统计农产品 void operator_summary(Product* head) { printf("\n=== 产品汇总 ===\n"); Product* current = head; int count = 1; while (current) { printf("%d. [ID:%d] %s (%s) 库存:%d\n", count++, current->id, current->name, current->type, current->stock_quantity); current = current->next; } if (count == 1) { printf("当前没有产品记录\n"); } }//汇总农产品 Member* operator_add_member(Member* head) { Member* new_mem = (Member*)malloc(sizeof(Member)); if (!new_mem) { printf("内存分配失败!\n"); return head; } // 输入编号 printf("请输入社员编号: "); scanf("%d", &new_mem->id); getchar(); // 清除输入缓冲区 // 输入姓名 printf("请输入姓名: "); fgets(new_mem->name, sizeof(new_mem->name), stdin); new_mem->name[strcspn(new_mem->name, "\n")] = '\0'; // 输入身份证号 printf("请输入身份证号: "); fgets(new_mem->id_card, sizeof(new_mem->id_card), stdin); new_mem->id_card[strcspn(new_mem->id_card, "\n")] = '\0'; // 输入手机号 printf("请输入手机号: "); fgets(new_mem->phone, sizeof(new_mem->phone), stdin); new_mem->phone[strcspn(new_mem->phone, "\n")] = '\0'; // 输入加入日期 printf("请输入加入日期: "); fgets(new_mem->join_date, sizeof(new_mem->join_date), stdin); new_mem->join_date[strcspn(new_mem->join_date, "\n")] = '\0'; // 插入链表头部 new_mem->next = head; return new_mem; }//增加社员 Member* operator_delete_member(Member* head, int target_id) { if (!head) { printf("当前没有社员记录\n"); return NULL; } Member *curr = head, *prev = NULL; while (curr) { if (curr->id == target_id) { if (prev) { prev->next = curr->next; } else { head = curr->next; } free(curr); printf("成功删除社员%d\n", target_id); return head; } prev = curr; curr = curr->next; } printf("未找到社员%d\n", target_id); return head; }//删除社员 void operator_modify_member(Member* head, int target_id) { Member* curr = head; while (curr) { if (curr->id == target_id) { printf("\n=== 修改社员 %d ===\n", target_id); printf("1. 修改姓名\n2. 修改手机号\n3. 修改入股金额\n4. 修改作物信息\n请选择: "); int choice; scanf("%d", &choice); getchar(); switch(choice) { case 1: printf("新姓名: "); fgets(curr->name, 30, stdin); curr->name[strcspn(curr->name, "\n")] = '\0'; break; case 2: printf("新手机号: "); fgets(curr->phone, 12, stdin); curr->phone[strcspn(curr->phone, "\n")] = '\0'; break; case 3: printf("新入股金额: "); scanf("%f", &curr->investment); getchar(); break; case 4: printf("新作物信息: "); fgets(curr->crops, 50, stdin); curr->crops[strcspn(curr->crops, "\n")] = '\0'; break; default: printf("无效选择\n"); } return; } curr = curr->next; } printf("未找到社员%d\n", target_id); }//修改社员信息 void print_member_details(Member* m); void operator_search_member(Member* head, int mode) { if (!head) { printf("当前没有社员记录\n"); return; } printf("\n=== 查询方式 ===\n"); printf("1.按编号查询\n2.按姓名查询\n请选择: "); scanf("%d", &mode); getchar(); char search_key[30]; int found = 0; if (mode == 1) { printf("请输入社员编号: "); int target_id; scanf("%d", &target_id); getchar(); Member* curr = head; while (curr) { if (curr->id == target_id) { print_member_details(curr); found = 1; break; } curr = curr->next; } } else if (mode == 2) { printf("请输入社员姓名: "); fgets(search_key, 30, stdin); search_key[strcspn(search_key, "\n")] = '\0'; Member* curr = head; while (curr) { if (strcmp(curr->name, search_key) == 0) { print_member_details(curr); found = 1; } curr = curr->next; } } if (!found) printf("未找到匹配记录\n"); } // 辅助打印函数 void print_member_details(Member* m) { printf("\n=== 社员详情 ===\n"); printf("编号: %d\n", m->id); printf("姓名: %s\n", m->name); printf("身份证: %s\n", m->id_card); printf("手机号: %s\n", m->phone); printf("入股金额: %.2f\n", m->investment); printf("种植作物: %s\n", m->crops); printf("加入日期: %s\n", m->join_date); }//查询社员 void operator_statistics_member(Member* head) { if (!head) { printf("当前没有社员记录\n"); return; } int total = 0; float total_invest = 0; Member* curr = head; while (curr) { total++; total_invest += curr->investment; curr = curr->next; } printf("\n=== 统计结果 ===\n"); printf("总社员数: %d\n", total); printf("总入股金额: %.2f\n", total_invest); printf("平均入股金额: %.2f\n", total_invest/total); }//统计社员信息 void operator_summary_member(Member* head) { if (!head) { printf("当前没有社员记录\n"); return; } printf("\n=== 社员汇总 ===\n"); printf("%-6s%-15s%-12s%-20s\n", "ID", "姓名", "手机号", "入股金额"); Member* curr = head; while (curr) { printf("%-6d%-15s%-12s%-20.2f\n", curr->id, curr->name, curr->phone, curr->investment); curr = curr->next; } }//汇总社员信息 // 添加库存记录 void operator_add_inventory_record() { InventoryRecord* new_record = (InventoryRecord*)malloc(sizeof(InventoryRecord)); if (!new_record) { printf("内存分配失败!\n"); return; } // 自动生成记录ID static int last_id = 0; new_record->record_id = ++last_id; // 输入基本信息 printf("输入农产品编号: "); scanf("%d", &new_record->product_id); getchar(); printf("选择操作类型(0-入库 1-出库 2-损耗): "); int type; scanf("%d", &type); new_record->op_type = (OperationType)type; getchar(); printf("输入变动数量: "); scanf("%d", &new_record->quantity); getchar(); printf("输入操作日期(YYYY-MM-DD): "); fgets(new_record->date, sizeof(new_record->date), stdin); new_record->date[strcspn(new_record->date, "\n")] = '\0'; printf("输入操作员姓名: "); fgets(new_record->operator, sizeof(new_record->operator), stdin); new_record->operator[strcspn(new_record->operator, "\n")] = '\0'; // 插入链表头部 new_record->next = inventory_head; inventory_head = new_record; printf("记录添加成功!\n"); } // 删除库存记录 void operator_delete_inventory_record(int target_id) { InventoryRecord *current = inventory_head, *prev = NULL; while (current) { if (current->record_id == target_id) { if (prev) { prev->next = current->next; } else { inventory_head = current->next; } free(current); printf("记录%d已删除!\n", target_id); return; } prev = current; current = current->next; } printf("未找到记录%d!\n", target_id); } // 修改库存记录 void operator_modify_inventory_record(int target_id) { InventoryRecord* current = inventory_head; while (current) { if (current->record_id == target_id) { printf("修改数量(当前值%d,直接回车跳过): ", current->quantity); char input[20]; fgets(input, sizeof(input), stdin); if (strlen(input) > 1) { current->quantity = atoi(input); } printf("修改日期(当前值%s): ", current->date); fgets(input, sizeof(input), stdin); if (strlen(input) > 1) { strncpy(current->date, input, 10); current->date[10] = '\0'; } printf("记录%d修改完成!\n", target_id); return; } current = current->next; } printf("未找到记录%d!\n", target_id); } // 查询库存记录 void operator_query_inventory_records() { int choice; printf("查询方式:\n1.按记录ID\n2.按农产品ID\n3.按日期范围\n4.按操作类型\n选择: "); scanf("%d", &choice); getchar(); InventoryRecord* current = inventory_head; int count = 0; switch (choice) { case 1: { int target_id; printf("输入记录ID: "); scanf("%d", &target_id); while (current) { if (current->record_id == target_id) { printf("[ID:%d] 产品:%d 类型:%d 数量:%d 日期:%s 操作员:%s\n", current->record_id, current->product_id, current->op_type, current->quantity, current->date, current->operator); count++; break; } current = current->next; } break; } case 2: { int product_id; printf("输入农产品ID: "); scanf("%d", &product_id); while (current) { if (current->product_id == product_id) { printf("[ID:%d] 类型:%d 数量:%d 日期:%s\n", current->record_id, current->op_type, current->quantity, current->date); count++; } current = current->next; } break; } case 3: { char start[11], end[11]; printf("输入开始日期(YYYY-MM-DD): "); fgets(start, sizeof(start), stdin); start[strcspn(start, "\n")] = '\0'; printf("输入结束日期(YYYY-MM-DD): "); fgets(end, sizeof(end), stdin); end[strcspn(end, "\n")] = '\0'; while (current) { if (strcmp(current->date, start) >= 0 && strcmp(current->date, end) <= 0) { printf("[ID:%d] 产品:%d 类型:%d 数量:%d 日期:%s\n", current->record_id, current->product_id, current->op_type, current->quantity, current->date); count++; } current = current->next; } break; } case 4: { int type; printf("输入操作类型(0-入库 1-出库 2-损耗): "); scanf("%d", &type); while (current) { if (current->op_type == type) { printf("[ID:%d] 产品:%d 数量:%d 日期:%s\n", current->record_id, current->product_id, current->quantity, current->date); count++; } current = current->next; } break; } default: printf("无效选择!\n"); return; } printf("共找到%d条记录\n", count); } // 统计汇总 void operator_inventory_summary() { int product_id; printf("输入要统计的农产品ID: "); scanf("%d", &product_id); int total_in = 0, total_out = 0, total_loss = 0; InventoryRecord* current = inventory_head; while (current) { if (current->product_id == product_id) { switch (current->op_type) { case INBOUND: total_in += current->quantity; break; case OUTBOUND: total_out += abs(current->quantity); break; case LOSS: total_loss += abs(current->quantity); break; } } current = current->next; } printf("\n=== 产品%d库存汇总 ===\n", product_id); printf("总入库量: %d\n", total_in); printf("总出库量: %d\n", total_out); printf("总损耗量: %d\n", total_loss); printf("当前库存: %d\n", total_in - total_out - total_loss); } // 生成唯一订单ID int generate_order_id() { static int counter = 1000; return counter++; } int date_compare(const char* date1, const char* date2); // 辅助函数:打印销售记录 void print_sales_record(SalesRecord* record); // 添加销售记录 void operator_add_sales_record() { SalesRecord* new_record = (SalesRecord*)malloc(sizeof(SalesRecord)); new_record->order_id = generate_order_id(); printf("输入农产品编号: "); scanf("%d", &new_record->product_id); printf("输入买家编号: "); scanf("%d", &new_record->buyer_id); printf("输入销售数量: "); scanf("%f", &new_record->quantity); printf("输入销售单价: "); scanf("%f", &new_record->unit_price); new_record->total_amount = new_record->quantity * new_record->unit_price; printf("输入销售日期(YYYY-MM-DD): "); scanf("%19s", new_record->sale_date); new_record->status = ORDER_PENDING; new_record->next = sales_head; sales_head = new_record; printf("订单%d添加成功!\n", new_record->order_id); } //删除销售记录 void operator_delete_sales_record(int order_id) { SalesRecord *current = sales_head, *prev = NULL; while (current) { if (current->order_id == order_id) { if (prev) prev->next = current->next; else sales_head = current->next; free(current); printf("订单%d已删除!\n", order_id); return; } prev = current; current = current->next; } printf("未找到订单%d!\n", order_id); } //修改销售记录 void operator_modify_sales_record(int order_id) { SalesRecord* current = sales_head; while (current) { if (current->order_id == order_id) { printf("输入新数量: "); scanf("%f", &current->quantity); current->total_amount = current->quantity * current->unit_price; printf("输入新状态(0-3): "); scanf("%d", (int*)&current->status); printf("订单%d修改完成!\n", order_id); return; } current = current->next; } printf("未找到订单%d!\n", order_id); } // 查询销售记录 void operator_query_sales() { int choice; printf("查询方式:\n1.按订单号\n2.按产品\n3.按买家\n4.按日期范围\n5.按状态\n选择: "); scanf("%d", &choice); int count = 0; SalesRecord* current = sales_head; time_t start_t = 0, end_t = 0; switch (choice) { case 1: { int target_id; printf("输入订单号: "); scanf("%d", &target_id); while (current) { if (current->order_id == target_id) { print_sales_record(current); count++; break; } current = current->next; } break; } case 2: { int product_id; printf("输入农产品编号: "); scanf("%d", &product_id); while (current) { if (current->product_id == product_id) { print_sales_record(current); count++; } current = current->next; } break; } case 3: { int buyer_id; printf("输入买家编号: "); scanf("%d", &buyer_id); while (current) { if (current->buyer_id == buyer_id) { print_sales_record(current); count++; } current = current->next; } break; } case 4: { char start_date[20], end_date[20]; printf("输入起始日期(YYYY-MM-DD): "); scanf("%19s", start_date); printf("输入结束日期(YYYY-MM-DD): "); scanf("%19s", end_date); while (current) { if (date_compare(current->sale_date, start_date) >= 0 && date_compare(current->sale_date, end_date) <= 0) { print_sales_record(current); count++; } current = current->next; } break; } case 5: { int status; printf("输入状态(0-3): "); scanf("%d", &status); while (current) { if (current->status == status) { print_sales_record(current); count++; } current = current->next; } break; } default: printf("无效选择!\n"); return; } printf("共找到%d条销售记录\n", count); } // 统计销售数据 void operator_sales_statistics() { float total_sales = 0; int status_counts[4] = {0}; SalesRecord* current = sales_head; while (current) { total_sales += current->total_amount; status_counts[current->status]++; current = current->next; } printf("\n=== 销售统计 ===\n"); printf("总销售额: %.2f\n", total_sales); printf("订单状态分布:\n"); printf(" 待处理: %d\n", status_counts[ORDER_PENDING]); printf(" 已发货: %d\n", status_counts[ORDER_SHIPPED]); printf(" 已完成: %d\n", status_counts[ORDER_COMPLETED]); printf(" 已取消: %d\n", status_counts[ORDER_CANCELED]); } // 辅助函数:打印销售记录 void print_sales_record(SalesRecord* record) { const char* status_names[] = {"待处理", "已发货", "已完成", "已取消"}; printf("[订单%d] 产品:%d 买家:%d\n 数量:%.2f 单价:%.2f 总金额:%.2f\n 状态:%s 日期:%s\n", record->order_id, record->product_id, record->buyer_id, record->quantity, record->unit_price, record->total_amount, status_names[record->status], record->sale_date); } // 辅助函数:获取状态名称 const char* get_status_name(OrderStatus status) { static const char* names[] = {"待处理", "已发货", "已完成", "已取消"}; return names[status]; } // 日期比较函数 int date_compare(const char* date1, const char* date2) { return strcmp(date1, date2); } //添加买家 void operator_add_buyer() { Buyer* new_buyer = (Buyer*)malloc(sizeof(Buyer)); static int last_id = 1000; new_buyer->buyer_id = ++last_id; printf("输入买家名称: "); fgets(new_buyer->name, 50, stdin); new_buyer->name[strcspn(new_buyer->name, "\n")] = '\0'; printf("选择类型(0-个人/1-企业): "); int type; scanf("%d", &type); getchar(); new_buyer->buyer_type = (BuyerType)type; printf("输入联系方式: "); fgets(new_buyer->contact, 30, stdin); new_buyer->contact[strcspn(new_buyer->contact, "\n")] = '\0'; printf("输入收货地址: "); fgets(new_buyer->address, 100, stdin); new_buyer->address[strcspn(new_buyer->address, "\n")] = '\0'; new_buyer->next = buyer_head; buyer_head = new_buyer; printf("买家%d添加成功!\n", new_buyer->buyer_id); } //删除买家 void operator_delete_buyer(int target_id) { Buyer *current = buyer_head, *prev = NULL; while (current) { if (current->buyer_id == target_id) { if (prev) prev->next = current->next; else buyer_head = current->next; free(current); printf("买家%d已删除!\n", target_id); return; } prev = current; current = current->next; } printf("未找到买家%d!\n", target_id); } //修改买家信息 void operator_modify_buyer(int target_id) { Buyer* current = buyer_head; while (current) { if (current->buyer_id == target_id) { printf("修改名称(当前值: %s): ", current->name); char input[50]; fgets(input, 50, stdin); if (strlen(input) > 1) { input[strcspn(input, "\n")] = '\0'; strcpy(current->name, input); } printf("修改类型(当前值: %d): ", current->buyer_type); int type; scanf("%d", &type); getchar(); current->buyer_type = (BuyerType)type; printf("修改联系方式(当前值: %s): ", current->contact); fgets(current->contact, 30, stdin); current->contact[strcspn(current->contact, "\n")] = '\0'; printf("买家%d修改完成!\n", target_id); return; } current = current->next; } printf("未找到买家%d!\n", target_id); } //查询买家信息 void operator_query_buyers() { int choice; printf("查询方式:\n1.按ID\n2.按名称\n3.按类型\n4.按地址关键字\n选择: "); scanf("%d", &choice); getchar(); int count = 0; Buyer* current = buyer_head; switch (choice) { case 1: { int target_id; printf("输入买家ID: "); scanf("%d", &target_id); while (current) { if (current->buyer_id == target_id) { printf("[ID:%d] 名称:%s\n", current->buyer_id, current->name); count++; break; } current = current->next; } break; } case 2: { char keyword[50]; printf("输入名称关键字: "); fgets(keyword, 50, stdin); keyword[strcspn(keyword, "\n")] = '\0'; while (current) { if (strstr(current->name, keyword)) { printf("[ID:%d] 名称:%s\n", current->buyer_id, current->name); count++; } current = current->next; } break; } case 3: { int type; printf("选择类型(0-个人/1-企业): "); scanf("%d", &type); while (current) { if (current->buyer_type == type) { printf("[ID:%d] 名称:%s\n", current->buyer_id, current->name); count++; } current = current->next; } break; } case 4: { char keyword[100]; printf("输入地址关键字: "); fgets(keyword, 100, stdin); keyword[strcspn(keyword, "\n")] = '\0'; while (current) { if (strstr(current->address, keyword)) { printf("[ID:%d] 名称:%s\n", current->buyer_id, current->name); count++; } current = current->next; } break; } default: printf("无效选择!\n"); return; } printf("共找到%d条记录\n", count); } // 统计买家信息 void operator_buyer_statistics() { int individual_count = 0, enterprise_count = 0; Buyer* current = buyer_head; while (current) { if (current->buyer_type == INDIVIDUAL) { individual_count++; } else { enterprise_count++; } current = current->next; } printf("\n=== 买家统计 ===\n"); printf("个人买家数量: %d\n", individual_count); printf("企业买家数量: %d\n", enterprise_count); printf("总买家数量: %d\n", individual_count + enterprise_count); } // 辅助打印函数 void print_buyer(Buyer* buyer) { printf("[ID:%d] 名称:%s\n 类型:%s\n 联系方式:%s\n 地址:%s\n", buyer->buyer_id, buyer->name, buyer->buyer_type == INDIVIDUAL ? "个人" : "企业", buyer->contact, buyer->address); } 根据这些代码写出操作人员菜单
05-31
#ifndef Users_H #define Users_H #include "common.h" // 用户角色枚举 typedef enum { ROLE_ADMIN, // 管理员 ROLE_OPERATOR, // 操作员 ROLE_FINANCE // 财务人员 } UserRole; // 权限标志位(使用位域优化存储) typedef struct { unsigned int user_manage : 1; // 用户管理权限 unsigned int product_manage : 1; // 农产品管理 unsigned int member_manage : 1; // 社员管理 unsigned int inventory_manage : 1;// 库存管理 unsigned int sales_manage : 1; // 销售管理 unsigned int finance_manage : 1; // 财务管理 } Permissions; // 用户结构体 typedef struct User { int user_id; // 用户ID char username[32]; // 用户名(限制长度) char password[64]; // 密码(预留加密空间) UserRole role; // 用户角色 Permissions perm; // 权限配置 struct User* next; // 链表指针 } User; typedef enum LoginState { LOGGED_OUT, LOGGED_IN } LoginState; // 全局状态变量 extern User* current_user; extern LoginState login_state; // 全局用户链表头指针 User* user_list = NULL; const char* get_role_name(UserRole role); #endif #ifndef Sales_H #define Sales_H #include "common.h" // 订单状态枚举 typedef enum { ORDER_PENDING, // 待处理 ORDER_SHIPPED, // 已发货 ORDER_COMPLETED, // 已完成 ORDER_CANCELED // 已取消 } OrderStatus; // 销售记录结构体 typedef struct SalesRecord { int order_id; // 订单编号(唯一) int product_id; // 关联的农产品编号 int buyer_id; // 关联的买家编号 float quantity; // 销售数量(支持小数) float unit_price; // 单价 float total_amount; // 总金额(quantity * unit_price) OrderStatus status; // 订单状态 char sale_date[20]; // 销售日期(格式:YYYY-MM-DD) struct SalesRecord* next; // 链表指针 } SalesRecord; SalesRecord* sales_list = NULL; void add_sales_record();// 添加销售记录 void delete_sales_record();// 删除销售记录 void modify_sales_record();// 修改销售记录 void query_sales();// 查询销售记录 void sales_statistics();// 统计销售数据 #endif #ifndef Product_H #define Product_H #include "common.h" typedef struct Product { int id;//农产品编号 char name[30];//农产品名称 char type[20];//农产品类型 float price;//单价 char description[100];//农产品描述 int stock_quantity;//库存数量 struct Product *next;//指向下一个节点 }Product; //创建农产品结构体 Product* product_list = NULL; Product* add_product(Product* head); //添加农产品信息 Product* delete_product(Product* head, int target_id); //删除农产品信息 void search_product(Product* head, int target_id); //查询农产品信息 void modify_product(Product* head, int target_id); //修改农产品信息 void statistics(Product* head); //统计农产品信息 void summary(Product* head); //汇总农产品信息 #endif #ifndef MENU_H #define MENU_H #include "common.h" // 函数原型声明 void admin_main_menu(void); void operator_main_menu(void); void finance_management_menu(void); void role_based_menu(); User* add_user(); int delete_user(); void modify_permissions(); User* find_user_by_id(); void display_all_users(); User* current_user = NULL; LoginState login_state = LOGGED_OUT; #endif #ifndef Member_H #define Member_H #include "common.h" typedef struct Member { int id; // 社员编号 char name[30]; // 社员姓名 char id_card[19]; // 身份证号(18位+结束符) char phone[12]; // 联系方式(11位手机号) float investment; // 入股金额 char crops[50]; // 种植作物信息(多个作物用逗号分隔) char join_date[11]; // 加入日期(YYYY-MM-DD格式) struct Member *next; // 链表指针 } Member; //创建社员结构体 Member* member_list = NULL; Member* add_member(Member* head); //添加社员信息 Member* delete_member(Member* head, int target_id); //删除社员信息 void modify_member(Member* head, int target_id); //修改社员信息 void search_member(Member* head, int mode); //查询社员信息 void statistics_member(Member* head); //统计社员信息 void summary_member(Member* head); //汇总社员信息 #endif #ifndef Inventory_H #define Inventory_H #include "common.h" typedef enum { INBOUND, // 入库 OUTBOUND, // 出库 LOSS // 损耗 } OperationType; // 库存记录结构体 typedef struct InventoryRecord { int record_id; // 记录编号(唯一标识) int product_id; // 关联的农产品编号 OperationType op_type; // 操作类型 int quantity; // 变动数量(正数表示增加,负数表示减少) char date[11]; // 操作日期(YYYY-MM-DD格式) char operator[20]; // 操作员姓名/ID struct InventoryRecord* next; // 链表指针 } InventoryRecord; InventoryRecord* inventory_list = NULL; void add_inventory_record(); void delete_inventory_record(int target_id); void modify_inventory_record(int target_id); void query_inventory_records(); void inventory_summary(); #endif #ifndef Finance_H #define Finance_H #include "common.h" // 财务类型 typedef enum { FINANCE_INCOME, // 收入(关联销售订单) FINANCE_EXPENSE, // 支出(关联采购/损耗) } FinanceType; // 财务记录结构体 typedef struct FinancialRecord { int record_id; // 记录编号(唯一) FinanceType type; // 财务类型 double amount; // 金额(支持正负) char record_date[20]; // 日期(YYYY-MM-DD) int related_order; // 关联的销售订单ID(收入时使用) int related_stock; // 关联的库存记录ID(支出时使用) char operator[20]; // 操作员ID struct FinancialRecord* next; // 链表指针 } FinancialRecord; void add_finance_record();// 添加财务记录 void delete_finance_record();// 删除财务记录 void modify_finance_record();// 修改财务记录 void query_finance();// 查询财务记录 void finance_statistics();// 统计财务数据 // 验证函数原型 int validate_finance_date(const char* date); int validate_amount(double amount); int validate_finance_type(FinanceType type); #endif #ifndef Common_H #define Common_H #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdbool.h> #include <time.h> #include <ctype.h> #include "product.h" #include "member.h" #include "inventory.h" #include "buyer.h" #include "sales.h" #include "finance.h" #include "user.h" #endif #include "user.h" // 添加新用户(返回新用户指针) User* add_user(const char* username, const char* password, UserRole role) { // 检查用户名是否已存在 User* current = user_list; while (current != NULL) { if (strcmp(current->username, username) == 0) { printf("错误:用户名 '%s' 已存在!\n", username); return NULL; } current = current->next; } // 创建新用户节点 User* new_user = (User*)malloc(sizeof(User)); if (!new_user) { perror("内存分配失败"); exit(EXIT_FAILURE); } // 自动生成用户ID(找最大值+1) static int last_id = 1000; new_user->user_id = ++last_id; // 设置基础信息 strncpy(new_user->username, username, sizeof(new_user->username)-1); strncpy(new_user->password, password, sizeof(new_user->password)-1); new_user->role = role; new_user->next = NULL; // 设置默认权限(根据角色) memset(&new_user->perm, 0, sizeof(Permissions)); switch(role) { case ROLE_ADMIN: new_user->perm = (Permissions){1,1,1,1,1,1}; // 所有权限 break; case ROLE_OPERATOR: new_user->perm = (Permissions){0,1,1,1,1,0}; // 业务操作权限 break; case ROLE_FINANCE: new_user->perm = (Permissions){0,0,0,0,0,1}; // 仅财务权限 break; } // 插入链表头部 if (user_list == NULL) { user_list = new_user; } else { new_user->next = user_list; user_list = new_user; } printf("用户 %s 添加成功!ID:%d\n", username, new_user->user_id); return new_user; } // 删除用户(按用户ID) int delete_user(int user_id) { User *current = user_list, *prev = NULL; while (current != NULL) { if (current->user_id == user_id) { if (prev == NULL) { // 删除头节点 user_list = current->next; } else { prev->next = current->next; } free(current); printf("用户 ID %d 已删除\n", user_id); return 1; } prev = current; current = current->next; } printf("未找到用户 ID %d\n", user_id); return 0; } // 修改用户权限(按用户ID) void modify_permissions(int user_id, Permissions new_perm) { User* user = find_user_by_id(user_id); if (user) { if (user->role == ROLE_ADMIN) { printf("警告:管理员权限不可修改!\n"); return; } user->perm = new_perm; printf("用户 %d 权限已更新\n", user_id); } else { printf("用户 ID %d 不存在\n", user_id); } } // 查询用户(按用户ID) User* find_user_by_id(int user_id) { User* current = user_list; while (current != NULL) { if (current->user_id == user_id) { return current; } current = current->next; } return NULL; } // 显示所有用户信息 void display_all_users() { printf("\n%-8s %-20s %-12s %s\n", "用户ID", "用户名", "角色", "权限"); printf("-------------------------------------------------\n"); User* current = user_list; while (current != NULL) { // 角色名称转换 const char* role_str = ""; switch(current->role) { case ROLE_ADMIN: role_str = "管理员"; break; case ROLE_OPERATOR: role_str = "操作员"; break; case ROLE_FINANCE: role_str = "财务"; break; } // 权限详情转换 char perm_buf[100]; snprintf(perm_buf, sizeof(perm_buf), "用户:%d 产品:%d 社员:%d 库存:%d 销售:%d 财务:%d", current->perm.user_manage, current->perm.product_manage, current->perm.member_manage, current->perm.inventory_manage, current->perm.sales_manage, current->perm.finance_manage); printf("%-8d %-20s %-12s %s\n", current->user_id, current->username, role_str, perm_buf); current = current->next; } printf("-------------------------------------------------\n"); } #include "buyer.h" void print_buyer(Buyer* buyer); //打印函数 //添加买家 void add_buyer(){ Buyer* new_buyer = (Buyer*)malloc(sizeof(Buyer)); static int last_id = 1000; new_buyer->buyer_id = ++last_id; printf("输入买家名称: "); fgets(new_buyer->name, 50, stdin); new_buyer->name[strcspn(new_buyer->name, "\n")] = '\0'; printf("选择类型(0-个人/1-企业): "); int type; scanf("%d", &type); getchar(); new_buyer->buyer_type = (BuyerType)type; printf("输入联系方式: "); fgets(new_buyer->contact, 30, stdin); new_buyer->contact[strcspn(new_buyer->contact, "\n")] = '\0'; printf("输入收货地址: "); fgets(new_buyer->address, 100, stdin); new_buyer->address[strcspn(new_buyer->address, "\n")] = '\0'; new_buyer->next = buyer_head; buyer_head = new_buyer; printf("买家%d添加成功!\n", new_buyer->buyer_id); } //删除买家 void delete_buyer(int target_id) { Buyer *current = buyer_head, *prev = NULL; while (current) { if (current->buyer_id == target_id) { if (prev) prev->next = current->next; else buyer_head = current->next; free(current); printf("买家%d已删除!\n", target_id); return; } prev = current; current = current->next; } printf("未找到买家%d!\n", target_id); } //修改买家信息 void modify_buyer(int target_id) { Buyer* current = buyer_head; while (current) { if (current->buyer_id == target_id) { printf("修改名称(当前值: %s): ", current->name); char input[50]; fgets(input, 50, stdin); if (strlen(input) > 1) { input[strcspn(input, "\n")] = '\0'; strcpy(current->name, input); } printf("修改类型(当前值: %d): ", current->buyer_type); int type; scanf("%d", &type); getchar(); current->buyer_type = (BuyerType)type; printf("修改联系方式(当前值: %s): ", current->contact); fgets(current->contact, 30, stdin); current->contact[strcspn(current->contact, "\n")] = '\0'; printf("买家%d修改完成!\n", target_id); return; } current = current->next; } printf("未找到买家%d!\n", target_id); } //查询买家信息 void query_buyers() { int choice; printf("查询方式:\n1.按ID\n2.按名称\n3.按类型\n4.按地址关键字\n选择: "); scanf("%d", &choice); getchar(); int count = 0; Buyer* current = buyer_head; switch (choice) { case 1: { int target_id; printf("输入买家ID: "); scanf("%d", &target_id); while (current) { if (current->buyer_id == target_id) { printf("[ID:%d] 名称:%s\n", current->buyer_id, current->name); count++; break; } current = current->next; } break; } case 2: { char keyword[50]; printf("输入名称关键字: "); fgets(keyword, 50, stdin); keyword[strcspn(keyword, "\n")] = '\0'; while (current) { if (strstr(current->name, keyword)) { printf("[ID:%d] 名称:%s\n", current->buyer_id, current->name); count++; } current = current->next; } break; } case 3: { int type; printf("选择类型(0-个人/1-企业): "); scanf("%d", &type); while (current) { if (current->buyer_type == type) { printf("[ID:%d] 名称:%s\n", current->buyer_id, current->name); count++; } current = current->next; } break; } case 4: { char keyword[100]; printf("输入地址关键字: "); fgets(keyword, 100, stdin); keyword[strcspn(keyword, "\n")] = '\0'; while (current) { if (strstr(current->address, keyword)) { printf("[ID:%d] 名称:%s\n", current->buyer_id, current->name); count++; } current = current->next; } break; } default: printf("无效选择!\n"); return; } printf("共找到%d条记录\n", count); } // 统计买家信息 void buyer_statistics() { int individual_count = 0, enterprise_count = 0; Buyer* current = buyer_head; while (current) { if (current->buyer_type == INDIVIDUAL) { individual_count++; } else { enterprise_count++; } current = current->next; } printf("\n=== 买家统计 ===\n"); printf("个人买家数量: %d\n", individual_count); printf("企业买家数量: %d\n", enterprise_count); printf("总买家数量: %d\n", individual_count + enterprise_count); } // 辅助打印函数 void print_buyer(Buyer* buyer) { printf("[ID:%d] 名称:%s\n 类型:%s\n 联系方式:%s\n 地址:%s\n", buyer->buyer_id, buyer->name, buyer->buyer_type == INDIVIDUAL ? "个人" : "企业", buyer->contact, buyer->address); } #include "finance.h" // 生成唯一财务记录ID int generate_finance_id() { static int counter = 5000; return counter++; } void print_finance_record(FinancialRecord* record);// 辅助打印函数 // 添加财务记录 void add_finance_record() { FinancialRecord* new_record = (FinancialRecord*)malloc(sizeof(FinancialRecord)); new_record->record_id = generate_finance_id(); printf("财务类型 (0-收入 1-支出): "); scanf("%d", (int*)&new_record->type); printf("金额: "); scanf("%lf", &new_record->amount); printf("日期(YYYY-MM-DD): "); scanf("%19s", new_record->record_date); if (new_record->type == FINANCE_INCOME) { printf("关联销售订单ID: "); scanf("%d", &new_record->related_order); } else { printf("关联库存记录ID: "); scanf("%d", &new_record->related_stock); } new_record->next = finance_head; finance_head = new_record; printf("财务记录%d添加成功!\n", new_record->record_id); } //删除财务记录 void delete_finance_record(int record_id) { FinancialRecord *current = finance_head, *prev = NULL; while (current) { if (current->record_id == record_id) { if (prev) prev->next = current->next; else finance_head = current->next; free(current); printf("记录%d已删除!\n", record_id); return; } prev = current; current = current->next; } printf("未找到记录%d!\n", record_id); } // 修改财务记录 void modify_finance_record(int record_id) { FinancialRecord* current = finance_head; while (current) { if (current->record_id == record_id) { // 修改类型 printf("当前类型: %d 输入新类型 (0-收入 1-支出): ", current->type); int new_type; scanf("%d", &new_type); if (new_type >= FINANCE_INCOME && new_type <= FINANCE_EXPENSE) { current->type = new_type; } // 修改金额 printf("当前金额: %.2f 输入新金额: ", current->amount); double new_amount; scanf("%lf", &new_amount); current->amount = new_amount; printf("记录%d修改完成!\n", record_id); return; } current = current->next; } printf("未找到记录%d!\n", record_id); } // 查询财务记录 void query_finance() { int choice; printf("查询方式:\n1.按记录号\n2.按类型\n3.按日期范围\n4.按金额范围\n选择: "); scanf("%d", &choice); int count = 0; FinancialRecord* current = finance_head; switch (choice) { case 1: { int target_id; printf("输入记录号: "); scanf("%d", &target_id); while (current) { if (current->record_id == target_id) { print_finance_record(current); count++; break; } current = current->next; } break; } case 2: { int type; printf("类型 (0-收入 1-支出): "); scanf("%d", &type); while (current) { if (current->type == type) { print_finance_record(current); count++; } current = current->next; } break; } case 3: { char start_date[20], end_date[20]; printf("起始日期(YYYY-MM-DD): "); scanf("%19s", start_date); printf("结束日期(YYYY-MM-DD): "); scanf("%19s", end_date); while (current) { if (strcmp(current->record_date, start_date) >= 0 && strcmp(current->record_date, end_date) <= 0) { print_finance_record(current); count++; } current = current->next; } break; } case 4: { double min, max; printf("最小金额: "); scanf("%lf", &min); printf("最大金额: "); scanf("%lf", &max); while (current) { if (current->amount >= min && current->amount <= max) { print_finance_record(current); count++; } current = current->next; } break; } default: printf("无效选择!\n"); return; } printf("共找到%d条财务记录\n", count); } // 统计财务数据 void finance_statistics() { double total_income = 0, total_expense = 0; FinancialRecord* current = finance_head; while (current) { if (current->type == FINANCE_INCOME) { total_income += current->amount; } else { total_expense += current->amount; } current = current->next; } printf("\n=== 财务统计 ===\n"); printf("总收入: %.2f\n", total_income); printf("总支出: %.2f\n", total_expense); printf("净利润: %.2f\n", total_income + total_expense); } // 辅助打印函数 void print_finance_record(FinancialRecord* record) { printf("[记录%d] 类型:%s 金额:%.2f\n 日期:%s 关联ID:%d\n", record->record_id, record->type == FINANCE_INCOME ? "收入" : "支出", record->amount, record->record_date, record->type == FINANCE_INCOME ? record->related_order : record->related_stock); } #include "inventory.h" // 库存记录链表头指针 InventoryRecord* inventory_head = NULL; // 添加库存记录 void add_inventory_record() { InventoryRecord* new_record = (InventoryRecord*)malloc(sizeof(InventoryRecord)); if (!new_record) { printf("内存分配失败!\n"); return; } // 自动生成记录ID static int last_id = 0; new_record->record_id = ++last_id; // 输入基本信息 printf("输入农产品编号: "); scanf("%d", &new_record->product_id); getchar(); printf("选择操作类型(0-入库 1-出库 2-损耗): "); int type; scanf("%d", &type); new_record->op_type = (OperationType)type; getchar(); printf("输入变动数量: "); scanf("%d", &new_record->quantity); getchar(); printf("输入操作日期(YYYY-MM-DD): "); fgets(new_record->date, sizeof(new_record->date), stdin); new_record->date[strcspn(new_record->date, "\n")] = '\0'; printf("输入操作员姓名: "); fgets(new_record->operator, sizeof(new_record->operator), stdin); new_record->operator[strcspn(new_record->operator, "\n")] = '\0'; // 插入链表头部 new_record->next = inventory_head; inventory_head = new_record; printf("记录添加成功!\n"); } // 删除库存记录 void delete_inventory_record(int target_id) { InventoryRecord *current = inventory_head, *prev = NULL; while (current) { if (current->record_id == target_id) { if (prev) { prev->next = current->next; } else { inventory_head = current->next; } free(current); printf("记录%d已删除!\n", target_id); return; } prev = current; current = current->next; } printf("未找到记录%d!\n", target_id); } // 修改库存记录 void modify_inventory_record(int target_id) { InventoryRecord* current = inventory_head; while (current) { if (current->record_id == target_id) { printf("修改数量(当前值%d,直接回车跳过): ", current->quantity); char input[20]; fgets(input, sizeof(input), stdin); if (strlen(input) > 1) { current->quantity = atoi(input); } printf("修改日期(当前值%s): ", current->date); fgets(input, sizeof(input), stdin); if (strlen(input) > 1) { strncpy(current->date, input, 10); current->date[10] = '\0'; } printf("记录%d修改完成!\n", target_id); return; } current = current->next; } printf("未找到记录%d!\n", target_id); } // 查询库存记录 void query_inventory_records() { int choice; printf("查询方式:\n1.按记录ID\n2.按农产品ID\n3.按日期范围\n4.按操作类型\n选择: "); scanf("%d", &choice); getchar(); InventoryRecord* current = inventory_head; int count = 0; switch (choice) { case 1: { int target_id; printf("输入记录ID: "); scanf("%d", &target_id); while (current) { if (current->record_id == target_id) { printf("[ID:%d] 产品:%d 类型:%d 数量:%d 日期:%s 操作员:%s\n", current->record_id, current->product_id, current->op_type, current->quantity, current->date, current->operator); count++; break; } current = current->next; } break; } case 2: { int product_id; printf("输入农产品ID: "); scanf("%d", &product_id); while (current) { if (current->product_id == product_id) { printf("[ID:%d] 类型:%d 数量:%d 日期:%s\n", current->record_id, current->op_type, current->quantity, current->date); count++; } current = current->next; } break; } case 3: { char start[11], end[11]; printf("输入开始日期(YYYY-MM-DD): "); fgets(start, sizeof(start), stdin); start[strcspn(start, "\n")] = '\0'; printf("输入结束日期(YYYY-MM-DD): "); fgets(end, sizeof(end), stdin); end[strcspn(end, "\n")] = '\0'; while (current) { if (strcmp(current->date, start) >= 0 && strcmp(current->date, end) <= 0) { printf("[ID:%d] 产品:%d 类型:%d 数量:%d 日期:%s\n", current->record_id, current->product_id, current->op_type, current->quantity, current->date); count++; } current = current->next; } break; } case 4: { int type; printf("输入操作类型(0-入库 1-出库 2-损耗): "); scanf("%d", &type); while (current) { if (current->op_type == type) { printf("[ID:%d] 产品:%d 数量:%d 日期:%s\n", current->record_id, current->product_id, current->quantity, current->date); count++; } current = current->next; } break; } default: printf("无效选择!\n"); return; } printf("共找到%d条记录\n", count); } // 统计汇总 void inventory_summary() { int product_id; printf("输入要统计的农产品ID: "); scanf("%d", &product_id); int total_in = 0, total_out = 0, total_loss = 0; InventoryRecord* current = inventory_head; while (current) { if (current->product_id == product_id) { switch (current->op_type) { case INBOUND: total_in += current->quantity; break; case OUTBOUND: total_out += abs(current->quantity); break; case LOSS: total_loss += abs(current->quantity); break; } } current = current->next; } printf("\n=== 产品%d库存汇总 ===\n", product_id); printf("总入库量: %d\n", total_in); printf("总出库量: %d\n", total_out); printf("总损耗量: %d\n", total_loss); printf("当前库存: %d\n", total_in - total_out - total_loss); } #include "member.h" Member* add_member(Member* head) { Member* new_mem = (Member*)malloc(sizeof(Member)); if (!new_mem) { printf("内存分配失败!\n"); return head; } // 输入编号 printf("请输入社员编号: "); scanf("%d", &new_mem->id); getchar(); // 清除输入缓冲区 // 输入姓名 printf("请输入姓名: "); fgets(new_mem->name, sizeof(new_mem->name), stdin); new_mem->name[strcspn(new_mem->name, "\n")] = '\0'; // 输入身份证号 printf("请输入身份证号: "); fgets(new_mem->id_card, sizeof(new_mem->id_card), stdin); new_mem->id_card[strcspn(new_mem->id_card, "\n")] = '\0'; // 输入手机号 printf("请输入手机号: "); fgets(new_mem->phone, sizeof(new_mem->phone), stdin); new_mem->phone[strcspn(new_mem->phone, "\n")] = '\0'; // 输入加入日期 printf("请输入加入日期: "); fgets(new_mem->join_date, sizeof(new_mem->join_date), stdin); new_mem->join_date[strcspn(new_mem->join_date, "\n")] = '\0'; // 插入链表头部 new_mem->next = head; return new_mem; }//增加社员 Member* delete_member(Member* head, int target_id) { if (!head) { printf("当前没有社员记录\n"); return NULL; } Member *curr = head, *prev = NULL; while (curr) { if (curr->id == target_id) { if (prev) { prev->next = curr->next; } else { head = curr->next; } free(curr); printf("成功删除社员%d\n", target_id); return head; } prev = curr; curr = curr->next; } printf("未找到社员%d\n", target_id); return head; }//删除社员 void modify_member(Member* head, int target_id) { Member* curr = head; while (curr) { if (curr->id == target_id) { printf("\n=== 修改社员 %d ===\n", target_id); printf("1. 修改姓名\n2. 修改手机号\n3. 修改入股金额\n4. 修改作物信息\n请选择: "); int choice; scanf("%d", &choice); getchar(); switch(choice) { case 1: printf("新姓名: "); fgets(curr->name, 30, stdin); curr->name[strcspn(curr->name, "\n")] = '\0'; break; case 2: printf("新手机号: "); fgets(curr->phone, 12, stdin); curr->phone[strcspn(curr->phone, "\n")] = '\0'; break; case 3: printf("新入股金额: "); scanf("%f", &curr->investment); getchar(); break; case 4: printf("新作物信息: "); fgets(curr->crops, 50, stdin); curr->crops[strcspn(curr->crops, "\n")] = '\0'; break; default: printf("无效选择\n"); } return; } curr = curr->next; } printf("未找到社员%d\n", target_id); }//修改社员信息 void print_member_details(Member* m); void search_member(Member* head, int mode) { if (!head) { printf("当前没有社员记录\n"); return; } printf("\n=== 查询方式 ===\n"); printf("1.按编号查询\n2.按姓名查询\n请选择: "); scanf("%d", &mode); getchar(); char search_key[30]; int found = 0; if (mode == 1) { printf("请输入社员编号: "); int target_id; scanf("%d", &target_id); getchar(); Member* curr = head; while (curr) { if (curr->id == target_id) { print_member_details(curr); found = 1; break; } curr = curr->next; } } else if (mode == 2) { printf("请输入社员姓名: "); fgets(search_key, 30, stdin); search_key[strcspn(search_key, "\n")] = '\0'; Member* curr = head; while (curr) { if (strcmp(curr->name, search_key) == 0) { print_member_details(curr); found = 1; } curr = curr->next; } } if (!found) printf("未找到匹配记录\n"); } // 辅助打印函数 void print_member_details(Member* m) { printf("\n=== 社员详情 ===\n"); printf("编号: %d\n", m->id); printf("姓名: %s\n", m->name); printf("身份证: %s\n", m->id_card); printf("手机号: %s\n", m->phone); printf("入股金额: %.2f\n", m->investment); printf("种植作物: %s\n", m->crops); printf("加入日期: %s\n", m->join_date); }//查询社员 void statistics_member(Member* head) { if (!head) { printf("当前没有社员记录\n"); return; } int total = 0; float total_invest = 0; Member* curr = head; while (curr) { total++; total_invest += curr->investment; curr = curr->next; } printf("\n=== 统计结果 ===\n"); printf("总社员数: %d\n", total); printf("总入股金额: %.2f\n", total_invest); printf("平均入股金额: %.2f\n", total_invest/total); }//统计社员信息 void summary_member(Member* head) { if (!head) { printf("当前没有社员记录\n"); return; } printf("\n=== 社员汇总 ===\n"); printf("%-6s%-15s%-12s%-20s\n", "ID", "姓名", "手机号", "入股金额"); Member* curr = head; while (curr) { printf("%-6d%-15s%-12s%-20.2f\n", curr->id, curr->name, curr->phone, curr->investment); curr = curr->next; } }//汇总社员信息 #include "menu.h" // 管理员主菜单 void admin_main_menu() { int choice; do { printf("\n==== 管理员主菜单 ====\n"); printf("1. 用户管理\n"); printf("2. 退出登录\n"); printf("请选择操作: "); scanf("%d", &choice); getchar(); // 清除输入缓冲区 switch(choice) { case 1: user_management_menu(); break; case 2: printf("已退出登录\n"); return; default: printf("无效选择,请重新输入!\n"); } } while (1); } // 用户管理子菜单 void user_management_menu() { int sub_choice; do { printf("\n--- 用户管理 ---\n"); printf("1. 添加用户\n"); printf("2. 删除用户\n"); printf("3. 修改权限\n"); printf("4. 查询用户\n"); printf("5. 显示所有用户\n"); printf("6. 返回上级\n"); printf("请选择操作: "); scanf("%d", &sub_choice); getchar(); switch(sub_choice) { case 1: add_user(); break; case 2: delete_user(); break; case 3: modify_permissions(); break; case 4: find_user_by_id(); break; case 5: display_all_users(); break; case 6: return; default: printf("无效选择!\n"); } } while (1); } // 显示主菜单 void operator_main_menu (){ int system_running = 1; while (system_running) { clear_screen(); printf("\n=== 农产品合作社管理系统 ===\n"); printf("1. 农产品管理\n"); printf("2. 社员管理\n"); printf("3. 库存管理\n"); printf("4. 销售管理\n"); printf("5. 买家管理\n"); printf("0. 退出系统\n"); printf("请选择操作:"); int choice; scanf("%d", &choice); getchar(); // 清除输入缓冲区 switch (choice) { case 1: product_management_menu(); break; case 2: member_management_menu(); break; case 3: inventory_management_menu(); break; case 4: sales_management_menu(); break; case 5: buyer_management_menu(); break; case 0: system_running = 0; break; default: printf("无效选择,请重新输入!\n"); getchar(); // 等待用户确认 } } } void product_management_menu() { int sub_running = 1; while (sub_running) { clear_screen(); printf("\n=== 农产品管理 ===\n"); printf("1. 添加农产品\n"); printf("2. 删除农产品\n"); printf("3. 修改农产品\n"); printf("4. 查询农产品\n"); printf("5. 统计汇总\n"); printf("6. 显示所有产品\n"); printf("0. 返回主菜单\n"); printf("请选择操作:"); int choice, target_id; scanf("%d", &choice); getchar(); switch (choice) { case 1: product_head = add_product(product_head); break; case 2: printf("输入要删除的产品ID: "); scanf("%d", &target_id); product_head = delete_product(product_head, target_id); break; case 3: printf("输入要修改的产品ID: "); scanf("%d", &target_id); modify_product(product_head, target_id); break; case 4: printf("输入要查询的产品ID: "); scanf("%d", &target_id); search_product(product_head, target_id); break; case 5: statistics(product_head); break; case 6: summary(product_head); break; case 0: sub_running = 0; break; default: printf("无效选择!\n"); } printf("\n按任意键继续..."); getchar(); } } void member_management_menu(){ int choice; int running = 1; while (running) { printf("\n=== 社员管理系统 ===\n"); printf("1. 添加社员\n"); printf("2. 删除社员\n"); printf("3. 修改社员\n"); printf("4. 查询社员\n"); printf("5. 统计信息\n"); printf("6. 汇总显示\n"); printf("0. 返回主菜单\n"); printf("请选择操作:"); int target_id; switch (choice) { case 1: member_head = add_member(member_head); break; case 2: if (member_head) { target_id = safe_input_int("请输入要删除的社员编号: "); member_head = delete_member(member_head, target_id); } else { printf("当前没有社员记录!\n"); } break; case 3: if (member_head) { target_id = safe_input_int("请输入要修改的社员编号: "); modify_member(member_head, target_id); } else { printf("当前没有社员记录!\n"); } break; case 4: if (member_head) { int mode = safe_input_int("请选择查询方式(1-编号 2-姓名): "); search_member(member_head, mode); } else { printf("当前没有社员记录!\n"); } break; case 5: statistics_member(member_head); break; case 6: summary_member(member_head); break; case 0: running = 0; break; default: printf("无效选择,请重新输入!\n"); } if (choice != 0) { printf("\n按任意键继续..."); getchar(); // 等待用户确认 } } } void inventory_management_menu() { int sub_running = 1; while (sub_running) { clear_screen(); printf("\n=== 库存管理 ===\n"); printf("1. 添加库存记录\n"); printf("2. 删除库存记录\n"); printf("3. 修改库存记录\n"); printf("4. 查询库存记录\n"); printf("5. 库存统计\n"); printf("0. 返回主菜单\n"); printf("请选择操作:"); int choice, target_id; scanf("%d", &choice); getchar(); switch (choice) { case 1: add_inventory_record(); break; case 2: printf("输入要删除的记录ID: "); scanf("%d", &target_id); delete_inventory_record(target_id); break; case 3: printf("输入要修改的记录ID: "); scanf("%d", &target_id); modify_inventory_record(target_id); break; case 4: query_inventory_records(); break; case 5: inventory_summary(); break; case 0: sub_running = 0; break; default: printf("无效选择!\n"); } printf("\n按任意键继续..."); getchar(); } } // 买家管理主菜单 void buyer_management_menu() { int choice; int sub_running = 1; while (sub_running) { system("clear || cls"); // 清屏命令 printf("\n=== 买家管理系统 ===\n"); printf("1. 添加买家\n"); printf("2. 删除买家\n"); printf("3. 修改买家信息\n"); printf("4. 查询买家\n"); printf("5. 买家统计\n"); printf("6. 显示所有买家\n"); printf("0. 返回主菜单\n"); printf("请选择操作: "); choice = safe_input_int(""); int target_id; switch (choice) { case 1: add_buyer(buyer_head); break; case 2: if (buyer_head) { target_id = safe_input_int("请输入要删除的买家ID: "); delete_buyer(buyer_head, target_id); } else { printf("当前没有买家记录!\n"); } break; case 3: if (buyer_head) { target_id = safe_input_int("请输入要修改的买家ID: "); modify_buyer(buyer_head, target_id); } else { printf("当前没有买家记录!\n"); } break; case 4: query_buyers(buyer_head); break; case 5: buyer_statistics(buyer_head); break; case 6: print_all_buyers(buyer_head); break; case 0: sub_running = 0; break; default: printf("无效选择,请重新输入!\n"); } if (choice != 0) { printf("\n操作完成,按回车键继续..."); getchar(); // 等待用户确认 } } } void sales_management_menu(SalesRecord** head) { int choice; int sub_running = 1; while (sub_running) { system("clear || cls"); printf("\n=== 销售记录管理系统 ===\n"); printf("1. 添加销售记录\n"); printf("2. 删除销售记录\n"); printf("3. 修改销售记录\n"); printf("4. 查询销售记录\n"); printf("5. 销售统计\n"); printf("6. 显示所有记录\n"); printf("0. 返回主菜单\n"); printf("请选择操作: "); int target_id; switch (choice) { case 1: add_sales_record(sales_head); break; case 2: if (sales_head) { target_id = safe_input_int("请输入要删除的订单号: "); delete_sales_record(sales_head, target_id); } else { printf("当前没有销售记录!\n"); } break; case 3: if (sales_head) { target_id = safe_input_int("请输入要修改的订单号: "); modify_sales_record(sales_head, target_id); } else { printf("当前没有销售记录!\n"); } break; case 4: query_sales(sales_head); break; case 5: sales_statistics(sales_head); break; case 6: print_all_sales(sales_head); break; case 0: sub_running = 0; break; default: printf("无效选择,请重新输入!\n"); } if (choice != 0) { printf("\n操作完成,按回车键继续..."); while (getchar() != '\n'); // 清空输入缓冲区 getchar(); } } } int safe_input_int(const char* prompt) { char buffer[128]; int value; while (1) { printf("%s", prompt); if (fgets(buffer, sizeof(buffer), stdin)) { if (sscanf(buffer, "%d", &value) == 1) { return value; } } printf("无效输入,请重新输入整数!\n"); } } void finance_management_menu() { int choice; do { system("clear || cls"); printf("\n=== 财务管理系统 ===\n"); printf("1. 添加财务记录\n"); printf("2. 删除财务记录\n"); printf("3. 修改财务记录\n"); printf("4. 查询财务记录\n"); printf("5. 财务统计\n"); printf("6. 显示所有记录\n"); printf("0. 返回主菜单\n"); printf("请选择操作: "); int target_id; switch (choice) { case 1: add_finance_record(finance_head); break; case 2: if (finance_head) { target_id = safe_input_int("请输入要删除的记录号: "); delete_finance_record(finance_head, target_id); } else { printf("当前没有财务记录!\n"); } break; case 3: if (finance_head) { target_id = safe_input_int("请输入要修改的记录号: "); modify_finance_record(finance_head, target_id); } else { printf("当前没有财务记录!\n"); } break; case 4: personnel_query_finance(finance_head); break; case 5: personnel_finance_statistics(finance_head); break; case 6: print_all_finance(finance_head); break; case 0: break; default: printf("无效选择,请重新输入!\n"); } if (choice != 0) { printf("\n按回车键继续..."); while (getchar() != '\n'); // 清空输入缓冲区 getchar(); } } while (choice != 0); } // 获取角色名称的辅助函数 const char* get_role_name(UserRole role) { static const char* names[] = { "管理员", "操作员", "财务人员" }; return names[role]; } #include "product.h" Product* add_product(Product* head) { Product* new_node = (Product*)malloc(sizeof(Product)); if (!new_node) { printf("内存分配失败!\n"); return head; } printf("请输入产品ID: "); scanf("%d", &new_node->id); getchar(); // 清空输入缓冲区 printf("请输入产品名称: "); fgets(new_node->name, 30, stdin); new_node->name[strcspn(new_node->name, "\n")] = '\0'; // 去除换行符 printf("请输入产品类型: "); fgets(new_node->type, 20, stdin); new_node->type[strcspn(new_node->type, "\n")] = '\0'; printf("请输入价格: "); scanf("%f", &new_node->price); printf("请输入库存数量: "); scanf("%d", &new_node->stock_quantity); getchar(); printf("请输入产品描述: "); fgets(new_node->description, 100, stdin); new_node->description[strcspn(new_node->description, "\n")] = '\0'; new_node->next = head; return new_node; }//添加农产品 Product* delete_product(Product* head, int target_id) { Product *current = head, *prev = NULL; while (current) { if (current->id == target_id) { if (prev) { prev->next = current->next; } else { head = current->next; } free(current); printf("成功删除ID为%d的产品\n", target_id); return head; } prev = current; current = current->next; } printf("未找到ID为%d的产品\n", target_id); return head; }//删除农产品 void search_product(Product* head, int target_id) { Product* current = head; while (current) { if (current->id == target_id) { printf("\n=== 产品详情 ===\n"); printf("ID: %d\n", current->id); printf("名称: %s\n", current->name); printf("类型: %s\n", current->type); printf("价格: %.2f\n", current->price); printf("库存: %d\n", current->stock_quantity); printf("描述: %s\n", current->description); return; } current = current->next; } printf("未找到ID为%d的产品\n", target_id); }//查询农产品 void modify_product(Product* head, int target_id) { Product* current = head; while (current) { if (current->id == target_id) { printf("请输入新的产品名称: "); fgets(current->name, 30, stdin); current->name[strcspn(current->name, "\n")] = '\0'; printf("请输入新的产品类型: "); fgets(current->type, 20, stdin); current->type[strcspn(current->type, "\n")] = '\0'; printf("请输入新的价格: "); scanf("%f", &current->price); printf("请输入新的库存数量: "); scanf("%d", &current->stock_quantity); getchar(); printf("请输入新的产品描述: "); fgets(current->description, 100, stdin); current->description[strcspn(current->description, "\n")] = '\0'; printf("产品信息更新成功!\n"); return; } current = current->next; } printf("未找到ID为%d的产品\n", target_id); }//修改农产品 void statistics(Product* head) { float total_value = 0; int total_quantity = 0; Product* current = head; while (current) { total_quantity += current->stock_quantity; total_value += current->stock_quantity * current->price; current = current->next; } printf("\n=== 统计结果 ===\n"); printf("总库存数量: %d\n", total_quantity); printf("总库存价值: %.2f\n", total_value); }//统计农产品 void summary(Product* head) { printf("\n=== 产品汇总 ===\n"); Product* current = head; int count = 1; while (current) { printf("%d. [ID:%d] %s (%s) 库存:%d\n", count++, current->id, current->name, current->type, current->stock_quantity); current = current->next; } if (count == 1) { printf("当前没有产品记录\n"); } }//汇总农产品 #include "sales.h" // 生成唯一订单ID int generate_order_id() { static int counter = 1000; return counter++; } int date_compare(const char* date1, const char* date2);// 日期比较函数 const char* get_status_name(OrderStatus status);// 辅助函数:获取状态名称 void print_sales_record(SalesRecord* record);// 辅助函数:获取状态名称 // 添加销售记录 void add_sales_record() { SalesRecord* new_record = (SalesRecord*)malloc(sizeof(SalesRecord)); new_record->order_id = generate_order_id(); printf("输入农产品编号: "); scanf("%d", &new_record->product_id); printf("输入买家编号: "); scanf("%d", &new_record->buyer_id); printf("输入销售数量: "); scanf("%f", &new_record->quantity); printf("输入销售单价: "); scanf("%f", &new_record->unit_price); new_record->total_amount = new_record->quantity * new_record->unit_price; printf("输入销售日期(YYYY-MM-DD): "); scanf("%19s", new_record->sale_date); new_record->status = ORDER_PENDING; new_record->next = sales_head; sales_head = new_record; printf("订单%d添加成功!\n", new_record->order_id); } //删除销售记录 void delete_sales_record(int order_id) { SalesRecord *current = sales_head, *prev = NULL; while (current) { if (current->order_id == order_id) { if (prev) prev->next = current->next; else sales_head = current->next; free(current); printf("订单%d已删除!\n", order_id); return; } prev = current; current = current->next; } printf("未找到订单%d!\n", order_id); } //修改销售记录 void modify_sales_record(int order_id) { SalesRecord* current = sales_head; while (current) { if (current->order_id == order_id) { printf("输入新数量: "); scanf("%f", &current->quantity); current->total_amount = current->quantity * current->unit_price; printf("输入新状态(0-3): "); scanf("%d", (int*)&current->status); printf("订单%d修改完成!\n", order_id); return; } current = current->next; } printf("未找到订单%d!\n", order_id); } // 查询销售记录 void query_sales() { int choice; printf("查询方式:\n1.按订单号\n2.按产品\n3.按买家\n4.按日期范围\n5.按状态\n选择: "); scanf("%d", &choice); int count = 0; SalesRecord* current = sales_head; time_t start_t = 0, end_t = 0; switch (choice) { case 1: { int target_id; printf("输入订单号: "); scanf("%d", &target_id); while (current) { if (current->order_id == target_id) { print_sales_record(current); count++; break; } current = current->next; } break; } case 2: { int product_id; printf("输入农产品编号: "); scanf("%d", &product_id); while (current) { if (current->product_id == product_id) { print_sales_record(current); count++; } current = current->next; } break; } case 3: { int buyer_id; printf("输入买家编号: "); scanf("%d", &buyer_id); while (current) { if (current->buyer_id == buyer_id) { print_sales_record(current); count++; } current = current->next; } break; } case 4: { char start_date[20], end_date[20]; printf("输入起始日期(YYYY-MM-DD): "); scanf("%19s", start_date); printf("输入结束日期(YYYY-MM-DD): "); scanf("%19s", end_date); while (current) { if (date_compare(current->sale_date, start_date) >= 0 && date_compare(current->sale_date, end_date) <= 0) { print_sales_record(current); count++; } current = current->next; } break; } case 5: { int status; printf("输入状态(0-3): "); scanf("%d", &status); while (current) { if (current->status == status) { print_sales_record(current); count++; } current = current->next; } break; } default: printf("无效选择!\n"); return; } printf("共找到%d条销售记录\n", count); } // 统计销售数据 void sales_statistics() { float total_sales = 0; int status_counts[4] = {0}; SalesRecord* current = sales_head; while (current) { total_sales += current->total_amount; status_counts[current->status]++; current = current->next; } printf("\n=== 销售统计 ===\n"); printf("总销售额: %.2f\n", total_sales); printf("订单状态分布:\n"); printf(" 待处理: %d\n", status_counts[ORDER_PENDING]); printf(" 已发货: %d\n", status_counts[ORDER_SHIPPED]); printf(" 已完成: %d\n", status_counts[ORDER_COMPLETED]); printf(" 已取消: %d\n", status_counts[ORDER_CANCELED]); } // 辅助函数:打印销售记录 void print_sales_record(SalesRecord* record) { const char* status_names[] = {"待处理", "已发货", "已完成", "已取消"}; printf("[订单%d] 产品:%d 买家:%d\n 数量:%.2f 单价:%.2f 总金额:%.2f\n 状态:%s 日期:%s\n", record->order_id, record->product_id, record->buyer_id, record->quantity, record->unit_price, record->total_amount, status_names[record->status], record->sale_date); } // 辅助函数:获取状态名称 const char* get_status_name(OrderStatus status) { static const char* names[] = {"待处理", "已发货", "已完成", "已取消"}; return names[status]; } // 日期比较函数 int date_compare(const char* date1, const char* date2) { return strcmp(date1, date2); } #include "common.h" int user_management_menu(); void role_based_menu(); void admin_main_menu(); void operator_main_menu (); void finance_management_menu(); void initialize_system(); User* user_login(); void free_resources(); FinancialRecord* finance_head = NULL; Buyer* buyer_head = NULL; InventoryRecord* inventory_head = NULL; Member* member_head = NULL; Product* product_head = NULL; SalesRecord* sales_head = NULL; // 登录验证函数 int login_system() { char username[32]; char password[64]; printf("\n======== 农业合作社管理系统 ========\n"); printf("用户名: "); fgets(username, sizeof(username), stdin); username[strcspn(username, "\n")] = '\0'; // 去除换行符 printf("密码: "); fgets(password, sizeof(password), stdin); password[strcspn(password, "\n")] = '\0'; // 遍历用户链表查找匹配 User* p = user_list; while (p != NULL) { if (strcmp(p->username, username) == 0 && strcmp(p->password, password) == 0) { current_user = p; login_state = LOGGED_IN; return 1; } p = p->next; } printf("登录失败,用户名或密码错误!\n"); return 0; } // 主菜单控制流程 void main_menu() { int choice; do { printf("\n==== 主菜单 ====\n"); printf("1. 登录系统\n"); printf("2. 退出程序\n"); printf("请选择操作: "); scanf("%d", &choice); getchar(); // 清除输入缓冲区 switch(choice) { case 1: if (login_system()) { role_based_menu(); } break; case 2: printf("系统已退出\n"); exit(0); default: printf("无效选择,请重新输入!\n"); } } while (1); } // 角色菜单分发器 void role_based_menu() { while (login_state == LOGGED_IN) { printf("\n===== 欢迎 %s [%s] =====\n", current_user->username, get_role_name(current_user->role)); switch(current_user->role) { case ROLE_ADMIN: admin_main_menu(); break; case ROLE_OPERATOR: operator_main_menu(); break; case ROLE_FINANCE: finance_management_menu(); break; default: printf("未知用户角色!\n"); login_state = LOGGED_OUT; } } } int main() { initialize_system(); current_user = user_login(); if (current_user) { printf("\n欢迎您,%s!\n", current_user->username); switch (current_user->role) { case ROLE_ADMIN: admin_main_menu(); break; case ROLE_OPERATOR: operator_main_menu(); break; case ROLE_FINANCE: finance_management_menu(); break; default: printf("未知用户角色!\n"); } } else { printf("登录失败,系统退出!\n"); } // 释放内存资源 free_resources(); return 0; } 这一大段全部代码有哪些错误
05-31
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值