package com.example.kucun2.entity.data;
import android.util.Log;
import androidx.annotation.NonNull;
import com.google.gson.Gson;
import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
/**
* 支持数据变更自动同步的泛型集合类
* @param <T> 继承自 SynchronizableEntity 的实体类型
*/
public class SynchronizedList<T extends SynchronizableEntity> implements List<T> {
private final List<T> list = new ArrayList<>();
private final OkHttpClient client = new OkHttpClient();
private static final Gson gson = new Gson();
private static final MediaType JSON = MediaType.get("application/json; charset=utf-8");
private final Class<T> entityClass; // 类型标记
// 添加批量操作模式标志
private boolean batchMode = false;
// 属性变更监听器
private final List<PropertyChangeListener<T>> listeners = new ArrayList<>();
// 直接接受Class参数的构造函数
public SynchronizedList(Class<T> entityClass) {
this.entityClass = entityClass;
}
// 安全的类型转换方法
private T safeCast(Object o) {
if (o != null && entityClass.isInstance(o)) {
return entityClass.cast(o);
}
return null;
}
public interface PropertyChangeListener<T> {
void onPropertyChange(T entity, String propertyName, Object oldValue, Object newValue);
}
public void addPropertyChangeListener(PropertyChangeListener<T> listener) {
listeners.add(listener);
}
public void removePropertyChangeListener(PropertyChangeListener<T> listener) {
listeners.remove(listener);
}
// 添加方法来获取原始对象
@SuppressWarnings("unchecked")
public T getOriginal(T proxy) {
if (proxy == null) return null;
// 检查是否为代理对象
if (java.lang.reflect.Proxy.isProxyClass(proxy.getClass())) {
try {
java.lang.reflect.InvocationHandler handler =
java.lang.reflect.Proxy.getInvocationHandler(proxy);
if (handler instanceof IProxyHandler) {
Object original = ((IProxyHandler) handler).getOriginal();
// 安全类型检查
if (entityClass.isInstance(original)) {
return (T) original;
}
}
} catch (Exception e) {
Log.e("SynchronizedList", "Failed to get proxy handler", e);
}
}
return proxy;
}
/**
* 同步实体到后端
*
* @param entity 要同步的实体
*/
private void syncEntity(T entity) {
if (batchMode) return;
String operation = "add";
T originalEntity = getOriginal(entity);
String endpoint = originalEntity.getEndpoint(operation);
String json = gson.toJson(originalEntity);
RequestBody body = RequestBody.create(json, JSON);
Request request = new Request.Builder()
.url(endpoint)
.method(getHttpMethod(operation), body)
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
Log.e("SynchronizedList", "同步失败: " + entity.getClass().getSimpleName(), e);
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) {
if (!response.isSuccessful()) {
Log.e("SynchronizedList", "同步失败: " +
response.code() + " - " + response.message());
}
response.close();
}
});
}
// 添加用于批量操作的方法
public void beginBatch() {
this.batchMode = true;
}
public void endBatch() {
this.batchMode = false;
// 批量结束后触发一次全量同步
syncAllEntities();
}
private void syncAllEntities() {
for (T entity : list) {
syncEntity(entity);
}
}
private String getHttpMethod(String operation) {
switch (operation) {
case "add":
return "POST";
case "update":
return "PUT";
case "delete":
return "DELETE";
default:
return "POST";
}
}
// 获取类实现的所有接口(包括父类接口)
private Class<?>[] getInterfaces(Class<?> clazz) {
Set<Class<?>> interfaces = new HashSet<>();
while (clazz != null) {
interfaces.addAll(Arrays.asList(clazz.getInterfaces()));
clazz = clazz.getSuperclass();
}
return interfaces.toArray(new Class<?>[0]);
}
/**
* 创建代理对象,用于监听属性变更
*/
// 优化 createProxy 方法
private T createProxy(T original) {
if (original == null) return null;
// 确保代理对象实现原始对象的所有接口+目标接口
Class<?>[] interfaces = new Class<?>[]{
SynchronizableEntity.class, // 强制实现目标接口
entityClass // 实体类或接口
};
// 使用动态代理实现接口
return (T) Proxy.newProxyInstance(
original.getClass().getClassLoader(),
new Class<?>[] { EntityClassGrassrootsid.class }, // 只代理接口
new EntityProxyHandler(original)
);
// if (!entityClass.isInstance(original)) {
// throw new IllegalArgumentException("Invalid entity type");
// }
// // 这里使用动态代理模式监听setter方法调用
// return (T) java.lang.reflect.Proxy.newProxyInstance(
// original.getClass().getClassLoader(),
// original.getClass().getInterfaces(),
// (proxy, method, args) -> {
// // 只拦截setter方法
// if (method.getName().startsWith("set") && args.length == 1) {
// String propertyName = method.getName().substring(3);
// propertyName = propertyName.substring(0, 1).toLowerCase() + propertyName.substring(1);
//
// // 获取旧值
// Object oldValue = original.getClass()
// .getMethod("get" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1))
// .invoke(original);
//
// // 调用原始方法
// Object result = method.invoke(original, args);
//
// // 触发监听器
// for (PropertyChangeListener<T> listener : listeners) {
// listener.onPropertyChange(original, propertyName, oldValue, args[0]);
// }
//
// // 自动同步到后端
// syncEntity(original);
// return result;
// }
// return method.invoke(original, args);
// }
// );
}
// 以下是List接口的实现
@Override
public int size() {
return list.size();
}
@Override
public boolean isEmpty() {
return list.isEmpty();
}
@Override
public boolean contains(Object o) {
return list.contains(o);
}
@NonNull
@Override
public Iterator<T> iterator() {
return list.iterator();
}
@NonNull
@Override
public Object[] toArray() {
return list.toArray();
}
@NonNull
@Override
public <T1> T1[] toArray(@NonNull T1[] a) {
return list.toArray(a);
}
@Override
public boolean add(T t) {
T proxy = createProxy(t);
boolean result = list.add(proxy);
if (!batchMode) {
syncEntity(proxy);
}
return result; // 添加时创建代理
}
@Override
public boolean remove(Object o) {
T entity = safeCast(o);
if (entity != null) {
syncEntity((T) entity); // 删除前同步
}
return list.remove(o);
}
@Override
public boolean containsAll(@NonNull Collection<?> c) {
return list.containsAll(c);
}
@Override
public boolean addAll(@NonNull Collection<? extends T> c) {
boolean modified = false;
for (T t : c) {
modified |= add(t);
}
return modified;
}
@Override
public boolean addAll(int index, @NonNull Collection<? extends T> c) {
for (T t : c) {
add(index++, t);
}
return true;
}
@Override
public boolean removeAll(@NonNull Collection<?> c) {
for (Object o : c) {
T entity = safeCast(o);
if (entity != null) {
syncEntity(entity);
}
}
return list.removeAll(c);
}
@Override
public boolean retainAll(@NonNull Collection<?> c) {
List<T> toRemove = new ArrayList<>();
for (T t : list) {
if (!c.contains(t)) {
toRemove.add(t);
}
}
// 使用安全转换
for (T entity : toRemove) {
syncEntity(entity);
}
return list.retainAll(c);
}
@Override
public void clear() {
for (T t : list) {
syncEntity(t); // 清空前同步
}
list.clear();
}
@Override
public T get(int index) {
return list.get(index);
}
@Override
public T set(int index, T element) {
T old = list.set(index, createProxy(element));
if (old != null) {
syncEntity(old); // 替换旧元素前同步
}
return old;
}
@Override
public void add(int index, T element) {
list.add(index, createProxy(element));
}
@Override
public T remove(int index) {
T removed = list.remove(index);
if (removed != null) {
syncEntity(removed); // 删除前同步
}
return removed;
}
@Override
public int indexOf(Object o) {
return list.indexOf(o);
}
@Override
public int lastIndexOf(Object o) {
return list.lastIndexOf(o);
}
@NonNull
@Override
public ListIterator<T> listIterator() {
return list.listIterator();
}
@NonNull
@Override
public ListIterator<T> listIterator(int index) {
return list.listIterator(index);
}
@NonNull
@Override
public List<T> subList(int fromIndex, int toIndex) {
return list.subList(fromIndex, toIndex);
}
// 触发属性变更通知
// 添加类型安全的属性监听
private void firePropertyChange(T entity, String propertyName, Object oldValue, Object newValue) {
if (oldValue != null && newValue != null && oldValue.equals(newValue)) {
return; // 值未变化时不触发监听
}
for (PropertyChangeListener<T> listener : listeners) {
try {
listener.onPropertyChange(entity, propertyName, oldValue, newValue);
} catch (Exception e) {
Log.e("SynchronizedList", "Listener error", e);
}
}
}
// 修改代理处理器以支持获取原始对象
/*
完整的 EntityProxyHandler
实现
*/
private class EntityProxyHandler implements IProxyHandler, java.lang.reflect.InvocationHandler {
private final T original;
private final Map<String, Object> propertyValues = new HashMap<>();
public EntityProxyHandler(T original) {
this.original = original;
cachePropertyValues();
}
private void cachePropertyValues() {
// 获取类信息
Class<?> clazz = original.getClass();
// 遍历所有getter方法
for (Method method : clazz.getMethods()) {
String methodName = method.getName();
// 只处理getter方法
if (methodName.startsWith("get") && !methodName.equals("getClass")
&& method.getParameterTypes().length == 0) {
try {
// 获取属性名(去掉"get"并将首字母小写)
String propertyName = methodName.substring(3);
propertyName = Character.toLowerCase(propertyName.charAt(0)) + propertyName.substring(1);
// 调用getter获取值
Object value = method.invoke(original);
propertyValues.put(propertyName, value);
} catch (Exception e) {
Log.e("Wrapper", "Failed to cache property " + methodName, e);
}
}
}
}
@Override
public T getOriginal() {
return original;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
// 只拦截setter方法
if (methodName.startsWith("set") && args != null && args.length == 1) {
String propertyName = methodName.substring(3);
propertyName = Character.toLowerCase(propertyName.charAt(0)) + propertyName.substring(1);
Object oldValue = propertyValues.get(propertyName);
Object newValue = args[0];
// 如果值未改变,不触发同步
if (Objects.equals(oldValue, newValue)) {
return null;
}
// 调用原始对象的setter方法
Method setter = original.getClass().getMethod(methodName, newValue.getClass());
setter.invoke(original, newValue);
// 更新属性缓存
propertyValues.put(propertyName, newValue);
// 触发属性变更监听
firePropertyChange(original, propertyName, oldValue, newValue);
// 非批量模式下自动同步
if (!batchMode) {
syncEntity(original);
}
}
// 其他接口方法直接调用原始对象
return method.invoke(original, args);
}
private Object getPropertyValue(String propertyName) {
String getterName = "get" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1);
try {
Method getter = original.getClass().getMethod(getterName);
return getter.invoke(original);
} catch (Exception e) {
Log.e("ProxyHandler", "Failed to get property value: " + propertyName, e);
return null;
}
}
}
// 在 SynchronizedList 类中添加
private interface IProxyHandler {
Object getOriginal();
}
}package com.example.kucun2.entity;
import android.annotation.SuppressLint;
import com.example.kucun2.entity.data.SynchronizableEntity;
import java.util.Objects;
//板材
public class Bancai extends SynchronizableEntity {
private Integer id;
private Caizhi caizhi;
private Mupi mupi1;
private Mupi mupi2;
private Double houdu;
public Bancai() {
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Bancai bancai = (Bancai) o;
return Objects.equals(id, bancai.id) && Objects.equals(caizhi, bancai.caizhi) && Objects.equals(mupi1, bancai.mupi1) && Objects.equals(mupi2, bancai.mupi2) && Objects.equals(houdu, bancai.houdu);
}
@Override
public int hashCode() {
return Objects.hash(id, caizhi, mupi1, mupi2, houdu);
}
public Bancai(Integer id, Caizhi caizhi, Mupi mupi1, Mupi mupi2, Double houdu) {
this.id = id;
this.caizhi = caizhi;
this.mupi1 = mupi1;
this.mupi2 = mupi2;
this.houdu = houdu;
}
public Integer getId() {
return id;
}
public Caizhi getCaizhi() {
return caizhi;
}
public Mupi getMupi1() {
return mupi1;
}
public Mupi getMupi2() {
return mupi2;
}
public Double getHoudu() {
return houdu;
}
public void setId(Integer id) {
this.id = id;
}
public void setCaizhi(Caizhi caizhi) {
this.caizhi = caizhi;
if (caizhi!=null&&caizhi.getBancais()!=null){
this.caizhi.getBancais().add(this);
}
}
public void setMupi1(Mupi mupi1) {
this.mupi1 = mupi1;
if (mupi1!=null&&mupi1.getBancais()!=null){
this.mupi1.getBancais().add(this);
}
}
public void setMupi2(Mupi mupi2) {
this.mupi2 = mupi2;
if (mupi2!=null&&mupi2.getBancais()!=null){
this.mupi2.getBancais().add(this);
}
}
public void setHoudu(Double houdu) {
this.houdu = houdu;
}
/**
* 表格中显示的文字
* @return
*/
@SuppressLint("DefaultLocale")
public String TableText(){
String boardInfo="";
boardInfo +=String.format("%.1f", this.getHoudu())+this.getCaizhi().getName()+"(";
if (mupi1 != null) {
boardInfo += (this.getMupi1().getYou()?this.getMupi1().getName()+"油":this.getMupi1().getName());
}
if (mupi2 != null&&mupi1 != null) {
boardInfo+=",";
}
if (mupi2 != null) {
boardInfo += (this.getMupi2().getYou()?this.getMupi2().getName()+"油":this.getMupi2().getName());
}
boardInfo+=")";
return boardInfo;
}
}
package com.example.kucun2.entity.data;
import com.example.kucun2.function.MyAppFnction;
public abstract class SynchronizableEntity implements EntityClassGrassrootsid {
/**
* 添加url
* @param type 操作增删改查
* @return 返回相对url
*/
public String getEndpoint(String type){
//从String.xml获取url
return MyAppFnction.getStringResource("String","url_"+type+"_"+this.getClass().getSimpleName());
}
}
package com.example.kucun2.ui.jinhuo;
import static android.content.ContentValues.TAG;
import android.app.AlertDialog;
import android.app.DatePickerDialog;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.MultiAutoCompleteTextView;
import android.widget.RadioGroup;
import android.widget.SearchView;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import com.example.kucun2.R;
import com.example.kucun2.entity.*;
import com.example.kucun2.entity.data.Data;
import com.example.kucun2.function.Adapter;
import com.google.android.material.textfield.TextInputEditText;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.Random;
public class AddInventoryFragment extends Fragment {
private Spinner spinnerDingdan, spinnerChanpin, spinnerZujian, spinnerBancai;
private EditText etShuliang;
private RadioGroup rgType;
private Dingdan selectedDingdan;
private Chanpin selectedChanpin;
private Zujian selectedZujian;
private Bancai selectedBancai;
// 创建新订单产品组件按钮
private Button btnNewDingdan, btnAddChanpin, btnAddZujian;
// 日期格式化
private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
/**
* 初始化
* @param inflater The LayoutInflater object that can be used to inflate
* any views in the fragment,
* @param container If non-null, this is the parent view that the fragment's
* UI should be attached to. The fragment should not add the view itself,
* but this can be used to generate the LayoutParams of the view.
* @param savedInstanceState If non-null, this fragment is being re-constructed
* from a previous saved state as given here.
*
* @return
*/
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_add_inventory, container, false);
// 初始化UI组件
spinnerDingdan = view.findViewById(R.id.spinner_dingdan);
spinnerChanpin = view.findViewById(R.id.spinner_chanpin);
spinnerZujian = view.findViewById(R.id.spinner_zujian);
spinnerBancai = view.findViewById(R.id.spinner_bancai);
etShuliang = view.findViewById(R.id.et_shuliang);
rgType = view.findViewById(R.id.rg_type);
Button btnSubmit = view.findViewById(R.id.btn_submit);
// 初始化新按钮
btnNewDingdan = view.findViewById(R.id.btn_new_dingdan);
btnAddChanpin = view.findViewById(R.id.btn_add_chanpin);
btnAddZujian = view.findViewById(R.id.btn_add_zujian);
// 设置按钮点击事件
btnNewDingdan.setOnClickListener(v -> createNewDingdan());
btnAddChanpin.setOnClickListener(v -> showAddChanpinDialog());
btnAddZujian.setOnClickListener(v -> addZujianToChanpin());
// 设置订单选择器
setupDingdanSpinner();
// 提交按钮点击事件
btnSubmit.setOnClickListener(v -> addInventoryRecord());
return view;
}
private void setupDingdanSpinner() {
Adapter.setupDingdanSpinner(spinnerDingdan,Data.dingdans,getContext());
spinnerDingdan.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
selectedDingdan = (Dingdan) parent.getItemAtPosition(position);
setupChanpinSpinner(selectedDingdan);
}
@Override
public void onNothingSelected(AdapterView<?> parent) {}
});
}
private void setupChanpinSpinner(Dingdan dingdan) {
// 获取该订单的产品列表
List<Chanpin> chanpins = new ArrayList<>();
for (Dingdan_Chanpin dc : dingdan.getChanpins()) {
chanpins.add(dc.getChanpin());
}
Adapter.setupChanpinSpinner(spinnerChanpin,chanpins,getContext());
spinnerChanpin.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
selectedChanpin = (Chanpin) parent.getItemAtPosition(position);
setupZujianSpinner(selectedChanpin);
}
@Override
public void onNothingSelected(AdapterView<?> parent) {}
});
}
/**
* 组件下拉框刷新
* @param chanpin
*/
private void setupZujianSpinner(Chanpin chanpin) {
// 获取该产品的组件列表
List<Zujian> zujians = new ArrayList<>();
for (Chanpin_Zujian cz : chanpin.getZujians()) {
zujians.add(cz.getZujian());
}
Adapter.setupZujianSpinner(spinnerZujian,zujians,getContext());
spinnerZujian.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
selectedZujian = (Zujian) parent.getItemAtPosition(position);
setupBancaiSpinner(selectedChanpin, selectedZujian);
}
@Override
public void onNothingSelected(AdapterView<?> parent) {}
});
}
/**
* 板材刷新
* @param chanpin
* @param zujian
*/
private void setupBancaiSpinner(Chanpin chanpin, Zujian zujian) {
// 获取该组件关联的板材
List<Bancai> bancais = new ArrayList<>();
for (Chanpin_Zujian cz : chanpin.getZujians()) {
if (cz.getZujian().getId().equals(zujian.getId())) {
bancais.add(cz.getBancai());
}
}
Adapter.setupBancaiSpinners(spinnerBancai,bancais,getContext());
spinnerBancai.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
selectedBancai = (Bancai) parent.getItemAtPosition(position);
}
@Override
public void onNothingSelected(AdapterView<?> parent) {}
});
}
// ... addInventoryRecord和createRecord方法保持不变 ...
private void addInventoryRecord() {
// 验证必填项
if (selectedDingdan == null || selectedChanpin == null || selectedZujian == null || selectedBancai == null) {
Toast.makeText(getContext(), "请选择订单、产品、组件和板材", Toast.LENGTH_SHORT).show();
return;
}
String shuliangStr = etShuliang.getText().toString().trim();
if (shuliangStr.isEmpty()) {
Toast.makeText(getContext(), "请输入数量", Toast.LENGTH_SHORT).show();
return;
}
// 解析数量
int shuliang;
try {
shuliang = Integer.parseInt(shuliangStr);
} catch (NumberFormatException e) {
Toast.makeText(getContext(), "请输入有效的数量", Toast.LENGTH_SHORT).show();
return;
}
// 确定操作类型(进货或消耗)
boolean isJinhuo = rgType.getCheckedRadioButtonId() == R.id.rb_jinhuo;
// 实际开发中应从登录信息获取当前用户
User currentUser = new User(1, "当前用户", "user", "password",1);
// 创建记录
createRecord(selectedDingdan, selectedChanpin, selectedZujian, selectedBancai, shuliang, isJinhuo, currentUser);
Toast.makeText(getContext(), "记录添加成功", Toast.LENGTH_SHORT).show();
etShuliang.setText(""); // 清空输入框
}
private void createRecord(Dingdan dingdan, Chanpin chanpin, Zujian zujian, Bancai bancai,
int shuliang, boolean isJinhuo, User user) {
if (isJinhuo) {
// 创建进货记录
Jinhuo jinhuo = new Jinhuo();
jinhuo.setId(Data.jinhuoList.size() + 1);
jinhuo.setDingdan(dingdan);
jinhuo.setChanpin(chanpin);
jinhuo.setZujian(zujian);
jinhuo.setBancai(bancai);
jinhuo.setShuliang(shuliang);
jinhuo.setDate(new Date());
jinhuo.setUser(user);
Data.jinhuoList.add(jinhuo);
} else {
// 消耗数量转为负数
shuliang = -shuliang;
}
// 更新库存
updateKucun(bancai, shuliang);
}
private void updateKucun(Bancai bancai, int changeAmount) {
// 查找现有库存记录
for (Kucun k : Data.kucuns) {
if (k.getBancai().getId().equals(bancai.getId())) {
k.setShuliang(k.getShuliang() + changeAmount);
return;
}
}
// 如果没有找到库存记录,创建新的
Kucun newKucun = new Kucun();
newKucun.setId(Data.kucuns.size() + 1);
newKucun.setBancai(bancai);
newKucun.setShuliang(Math.max(changeAmount, 0)); // 确保不为负
Data.kucuns.add(newKucun);
}
// 新建订单方法
private void createNewDingdan() {
showNewDingdanDialog();
}
/**
* 向订单添加产品
* @param chanpin
*/
private void addChanpinToDingdan(Chanpin chanpin) {
if (selectedDingdan == null) {
Toast.makeText(getContext(), "请先选择订单", Toast.LENGTH_SHORT).show();
return;
}
// 检查产品是否已在订单中
for (Dingdan_Chanpin dc : selectedDingdan.getChanpins()) {
if (dc.getChanpin().getId().equals(chanpin.getId())) {
Toast.makeText(getContext(), "该产品已添加到订单", Toast.LENGTH_SHORT).show();
return;
}
}
// 添加到当前订单的产品列表
Dingdan_Chanpin dc = new Dingdan_Chanpin();
dc.setId(selectedDingdan.getChanpins().size() + 1);
dc.setChanpin(chanpin);
dc.setDingdan(selectedDingdan);
selectedDingdan.getChanpins().add(dc);
// 刷新产品下拉框
setupChanpinSpinner(selectedDingdan);
// 选中新添加的产品
spinnerChanpin.setSelection(selectedDingdan.getChanpins().size() - 1);
Toast.makeText(getContext(), "产品添加成功", Toast.LENGTH_SHORT).show();
}
// 为当前产品添加组件
private void addZujianToChanpin() {
if (selectedChanpin == null) {
Toast.makeText(getContext(), "请先选择产品", Toast.LENGTH_SHORT).show();
return;
}
// // 创建新组件(示例)
// Zujian newZujian = new Zujian();
// newZujian.setId( (Data.zujians.size() + 1));
// newZujian.setName("新组件" + System.currentTimeMillis());
//
// // 添加到全局列表
// Data.zujians.add(newZujian);
//
// // 添加到当前产品的组件列表
// Chanpin_Zujian cz = new Chanpin_Zujian();
// cz.setId(selectedChanpin.getZujians().size() + 1);
// cz.setZujian(newZujian);
// cz.setChanpin(selectedChanpin);
// selectedChanpin.getZujians().add(cz);
//
// // 刷新组件下拉框
// setupZujianSpinner(selectedChanpin);
// spinnerZujian.setSelection(selectedChanpin.getZujians().size() - 1);
//
// Toast.makeText(getContext(), "组件添加成功", Toast.LENGTH_SHORT).show();
showCreateZujianDialog();
}
// 新建订单对话框
/***
* 新建订单对话框
*/
private void showNewDingdanDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(requireContext());
builder.setTitle("新建订单");
// 加载布局
View dialogView = LayoutInflater.from(requireContext()).inflate(R.layout.dialog_new_dingdan, null);
EditText etOrderNumber = dialogView.findViewById(R.id.et_order_number);
EditText etOrderDate = dialogView.findViewById(R.id.et_order_date);
EditText etDeliveryDate = dialogView.findViewById(R.id.et_delivery_date);
Button btnPickOrderDate = dialogView.findViewById(R.id.btn_pick_order_date);
Button btnPickDeliveryDate = dialogView.findViewById(R.id.btn_pick_delivery_date);
// 设置今日日期作为默认值
Date today = new Date();
etOrderDate.setText(dateFormat.format(today));
// 日期选择监听器
DatePickerDialog.OnDateSetListener orderDateListener = (view, year, month, dayOfMonth) -> {
Calendar cal = Calendar.getInstance();
cal.set(year, month, dayOfMonth);
etOrderDate.setText(dateFormat.format(cal.getTime()));
};
DatePickerDialog.OnDateSetListener deliveryDateListener = (view, year, month, dayOfMonth) -> {
Calendar cal = Calendar.getInstance();
cal.set(year, month, dayOfMonth);
etDeliveryDate.setText(dateFormat.format(cal.getTime()));
};
// 下单日期选择按钮
btnPickOrderDate.setOnClickListener(v -> {
Calendar cal = Calendar.getInstance();
new DatePickerDialog(requireContext(),
orderDateListener,
cal.get(Calendar.YEAR),
cal.get(Calendar.MONTH),
cal.get(Calendar.DAY_OF_MONTH))
.show();
});
/**
* / 出货日期选择按钮
*/
btnPickDeliveryDate.setOnClickListener(v -> {
Calendar cal = Calendar.getInstance();
new DatePickerDialog(requireContext(),
deliveryDateListener,
cal.get(Calendar.YEAR),
cal.get(Calendar.MONTH),
cal.get(Calendar.DAY_OF_MONTH))
.show();
});
builder.setView(dialogView);
builder.setPositiveButton("创建", (dialog, which) -> {
String orderNumber = etOrderNumber.getText().toString().trim();
String orderDateStr = etOrderDate.getText().toString();
String deliveryDateStr = etDeliveryDate.getText().toString();
for (Dingdan dingdan:Data.dingdans
) {
if(dingdan.getNumber().equals(orderNumber)){
Toast.makeText(getContext(), "已有该订单号", Toast.LENGTH_SHORT).show();
return;
}
}
// 验证输入
if (orderNumber.isEmpty()) {
Toast.makeText(getContext(), "请输入订单号", Toast.LENGTH_SHORT).show();
return;
}
try {
// 解析日期
Date orderDate = dateFormat.parse(orderDateStr);
Date deliveryDate = deliveryDateStr.isEmpty() ? null : dateFormat.parse(deliveryDateStr);
// 创建订单
createAndSaveDingdan(orderNumber, orderDate, deliveryDate);
} catch (ParseException e) {
Toast.makeText(getContext(), "日期格式错误", Toast.LENGTH_SHORT).show();
}
});
builder.setNegativeButton("取消", null);
builder.show();
}
/**
* 创建并保存订单
*/
private void createAndSaveDingdan(String orderNumber, Date orderDate, Date deliveryDate) {
Dingdan newDingdan = new Dingdan();
newDingdan.setId(Data.dingdans.size() + 1);
newDingdan.setNumber(orderNumber);
newDingdan.setXiadan(orderDate);
newDingdan.setJiaohuo(deliveryDate);
newDingdan.setChanpins(new ArrayList<>());
Data.dingdans.add(newDingdan);
// 刷新下拉框
setupDingdanSpinner();
spinnerDingdan.setSelection(Data.dingdans.size() - 1);
Toast.makeText(getContext(), "新建订单成功", Toast.LENGTH_SHORT).show();
}
/**
* 显示添加产品弹窗
*/
private void showAddChanpinDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(requireContext());
builder.setTitle("添加产品到订单");
// 加载布局
View dialogView = LayoutInflater.from(requireContext()).inflate(R.layout.dialog_add_chanpin, null);
Spinner spinnerChanpinSelection = dialogView.findViewById(R.id.spinner_chanpin_selection);
Button btnNewChanpin = dialogView.findViewById(R.id.btn_new_chanpin);
// 设置产品下拉框
Adapter.setupChanpinSpinner(spinnerChanpinSelection, Data.chanpins, getContext());
// 新建产品按钮点击事件
btnNewChanpin.setOnClickListener(v -> {
showNewChanpinDialog(() -> {
// 新建产品后刷新下拉框
Adapter.setupChanpinSpinner(spinnerChanpinSelection, Data.chanpins, getContext());
// 默认选中新建的产品
spinnerChanpinSelection.setSelection(Data.chanpins.size() - 1);
});
});
builder.setView(dialogView);
builder.setPositiveButton("添加", (dialog, which) -> {
Chanpin selectedChanpin = (Chanpin) spinnerChanpinSelection.getSelectedItem();
if (selectedChanpin != null) {
// 将选中的产品添加到当前订单
addChanpinToDingdan(selectedChanpin);
}
});
builder.setNegativeButton("取消", null);
builder.show();
}
/**
* 显示新建产品弹窗
* @param refreshCallback 新建后的回调,用于刷新产品列表
*/
private void showNewChanpinDialog(Runnable refreshCallback) {
AlertDialog.Builder builder = new AlertDialog.Builder(requireContext());
builder.setTitle("新建产品");
View dialogView = LayoutInflater.from(requireContext()).inflate(R.layout.dialog_new_chanpin, null);
EditText etChanpinName = dialogView.findViewById(R.id.et_chanpin_name);
builder.setView(dialogView);
builder.setPositiveButton("创建", (dialog, which) -> {
String chanpinName = etChanpinName.getText().toString().trim();
if (chanpinName.isEmpty()) {
Toast.makeText(getContext(), "请输入产品名称", Toast.LENGTH_SHORT).show();
return;
}
// 检查名称是否重复
for (Chanpin cp : Data.chanpins) {
if (cp.getName().equals(chanpinName)) {
Toast.makeText(getContext(), "产品名称重复", Toast.LENGTH_SHORT).show();
return;
}
}
// 创建新产品
Chanpin newChanpin = new Chanpin();
newChanpin.setId(Data.chanpins.size() + 1);
newChanpin.setName(chanpinName);
newChanpin.setZujians(new ArrayList<>());
Data.chanpins.add(newChanpin);
refreshCallback.run();
Toast.makeText(getContext(), "产品创建成功", Toast.LENGTH_SHORT).show();
});
builder.setNegativeButton("取消", null);
builder.show();
}
/**
* 添加新组件
*/
private void showCreateZujianDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(requireContext());
builder.setTitle("添加新组件");
// 创建自定义布局
View dialogView = LayoutInflater.from(requireContext()).inflate(R.layout.dialog_create_zujian_bancai, null);
EditText etZujianName = dialogView.findViewById(R.id.et_zujian_name);
Spinner spinnerbancai = dialogView.findViewById(R.id.spinner_bancai);
SearchView searchBancai = dialogView.findViewById(R.id.search_bancai);
Button btnAddBancai = dialogView.findViewById(R.id.btn_add_bancai);
// 设置添加板材按钮点击事件
btnAddBancai.setOnClickListener(v -> {
// 弹出添加板材的弹窗,并传入当前Spinner用于刷新
showCreateBancaiDialog(spinnerbancai);
});
// 板材适配器
Adapter.setupBancaiSpinners(spinnerbancai,Data.bancais,getContext());
// 设置搜索功能
searchBancai.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
// 过滤板材列表
List<Bancai> filteredList = new ArrayList<>();
for (Bancai bancai : Data.bancais) {
if ( bancai.TableText().toLowerCase().contains(newText.toLowerCase())) {
filteredList.add(bancai);
}
}
// 板材适配器
Adapter.setupBancaiSpinners(spinnerbancai,filteredList,getContext());
return true;
}
});
// 添加木皮预览标签
builder.setView(dialogView);
builder.setPositiveButton("创建", (dialog, which) -> {
// 获取用户输入
String zujianName = etZujianName.getText().toString().trim();
Bancai selectedBancai = (Bancai) spinnerbancai.getSelectedItem();
if (zujianName.isEmpty()) {
Toast.makeText(getContext(), "请输入组件名称", Toast.LENGTH_SHORT).show();
return;
}
// 创建新组件
Zujian newZujian = new Zujian();
newZujian.setId(Data.zujians.size() + 1);
newZujian.setName(zujianName);
// 创建新板材
// 添加到全局列表
Data.zujians.add(newZujian);
// 添加到当前产品的组件列表
Chanpin_Zujian cz = new Chanpin_Zujian();
cz.setId(selectedChanpin.getZujians().size() + 1);
cz.setZujian(newZujian);
cz.setBancai(selectedBancai); // 关联新创建的板材
cz.setChanpin(selectedChanpin);
selectedChanpin.getZujians().add(cz);
// 刷新组件下拉框
setupZujianSpinner(selectedChanpin);
spinnerZujian.setSelection(selectedChanpin.getZujians().size() - 1);
Toast.makeText(getContext(), "组件和板材添加成功", Toast.LENGTH_SHORT).show();
});
builder.setNegativeButton("取消", null);
builder.show();
}
// 显示创建板材的弹窗
private void showCreateBancaiDialog(Spinner spinnerToRefresh) {
AlertDialog.Builder builder = new AlertDialog.Builder(requireContext());
builder.setTitle("添加新板材");
// 加载布局
View dialogView = LayoutInflater.from(requireContext()).inflate(R.layout.dialog_create_bancai, null);
Spinner spinnerCaizhi = dialogView.findViewById(R.id.spinner_caizhi);
Spinner spinnerMupi1 = dialogView.findViewById(R.id.spinner_mupi1);
Spinner spinnerMupi2 = dialogView.findViewById(R.id.spinner_mupi2);
EditText TextInputEditTextHoudu=dialogView.findViewById(R.id.edittext_houdu);
TextInputEditTextHoudu.setTextIsSelectable(true);
// 绑定新建材质按钮
Button btnNewCaizhi = dialogView.findViewById(R.id.btn_new_caizhi);
btnNewCaizhi.setOnClickListener(v -> {
showNewOptionDialog("材质", option -> {
// 避免重复添加
for (Caizhi caizhi : Data.caizhis) {
if (caizhi.getName().equals(option)) return;
}
// 创建新材质
Caizhi newCaizhi = new Caizhi();
newCaizhi.setName(option);
newCaizhi.setId(Data.caizhis.size() + 1);
newCaizhi.setBancais(new ArrayList<>());
Data.caizhis.add(newCaizhi);
// 刷新下拉框
Adapter.setupCaizhiSpinner(spinnerCaizhi, Data.caizhis, requireContext());
spinnerCaizhi.setSelection(Data.caizhis.size() - 1);
});
});
// 绑定新建木皮按钮
Button btnNewMupi = dialogView.findViewById(R.id.btn_new_mupi);
btnNewMupi.setOnClickListener(v -> {
// 弹出新建木皮对话框
showNewMupiDialog(() -> {
// 回调中刷新木皮下拉框
Adapter.setupMupiSpinner(spinnerMupi1, Data.mupis, requireContext());
Adapter.setupMupiSpinner(spinnerMupi2, Data.mupis, requireContext());
});
});
// 获取所有材质选项(从现有板材中提取)
List<Caizhi> allCaizhi = Data.caizhis;
List<Mupi> allMupi = Data.mupis;
// 设置下拉框适配器
Adapter.setupCaizhiSpinner(spinnerCaizhi, allCaizhi, requireContext());
Adapter.setupMupiSpinner(spinnerMupi1, allMupi, requireContext());
Adapter.setupMupiSpinner(spinnerMupi2, allMupi, requireContext());
builder.setView(dialogView);
builder.setPositiveButton("创建", (dialog, which) -> {
Caizhi caizhi = (Caizhi)spinnerCaizhi.getSelectedItem() ;
Mupi mupi1 = (Mupi)spinnerMupi1.getSelectedItem() ;
Mupi mupi2 = (Mupi) spinnerMupi2.getSelectedItem() ;
// 获取 TextInputEditText 的内容并进行校验
String houduText = TextInputEditTextHoudu.getText().toString().trim();
Double houdu = null;
try {
if (!houduText.isEmpty()) { // 检查输入是否为空
houdu = Double.valueOf(houduText); // 尝试将字符串转换为 Double
}
} catch (NumberFormatException e) {
// 捕获转换异常并提示用户
Toast.makeText(getContext(), "厚度输入无效,请输入数字", Toast.LENGTH_SHORT).show();
return;
}
// 校验 caizhi 和 houdu 是否均有效
if (caizhi == null || houdu == null) {
Toast.makeText(getContext(), "请选择材质并输入有效的厚度", Toast.LENGTH_SHORT).show();
return;
}
// 创建新板材
Bancai newBancai = new Bancai();
newBancai.setId(Data.bancais.size() + 1);
newBancai.setCaizhi(caizhi);
newBancai.setMupi1(mupi1);
newBancai.setMupi2(mupi2);
newBancai.setHoudu(houdu);
caizhi.getBancais().add(newBancai);
if (mupi1 != null) {
mupi1.getBancais().add(newBancai);
}
if (mupi2 != null) {
mupi2.getBancais().add(newBancai);
}
// 添加到全局列表
Data.bancais.add(newBancai);
// 刷新Spinner(如果传入)
if (spinnerToRefresh != null) {
Adapter.setupBancaiSpinners(spinnerToRefresh, Data.bancais, getContext());
spinnerToRefresh.setSelection(Data.bancais.size() - 1);
}
Toast.makeText(getContext(), "板材添加成功", Toast.LENGTH_SHORT).show();
});
builder.setNegativeButton("取消", null);
builder.show();
}
// 显示新建选项的弹窗
/**
* 显示新建选项的弹窗
* @param type 新建什么
* @param listener 反回
*/
private void showNewOptionDialog(String type, OnOptionCreatedListener listener) {
AlertDialog.Builder builder = new AlertDialog.Builder(requireContext());
builder.setTitle("新建" + type);
final EditText input = new EditText(requireContext());
input.setHint("请输入" + type);
builder.setView(input);
builder.setPositiveButton("确定", (dialog, which) -> {
String option = input.getText().toString().trim();
if (!option.isEmpty()) {
listener.onOptionCreated(option);
}
});
builder.setNegativeButton("取消", null);
builder.show();
}
// 回调接口
interface OnOptionCreatedListener {
void onOptionCreated(String option);
}
// 新建木皮对话框
private void showNewMupiDialog(Runnable refreshCallback) {
AlertDialog.Builder builder = new AlertDialog.Builder(requireContext());
builder.setTitle("新建木皮");
View view = LayoutInflater.from(requireContext()).inflate(R.layout.dialog_new_mupi, null);
EditText etName = view.findViewById(R.id.et_mupi_name);
RadioGroup rgFinish = view.findViewById(R.id.rg_finish);
builder.setView(view);
builder.setPositiveButton("创建", (dialog, which) -> {
String name = etName.getText().toString().trim();
if (name.isEmpty()) {
Toast.makeText(getContext(), "请输入木皮名称", Toast.LENGTH_SHORT).show();
return;
}
// 避免重复添加
for (Mupi m : Data.mupis) {
if (m.getName().equals(name)) return;
}
// 创建木皮对象
Mupi newMupi = new Mupi();
newMupi.setId(Data.mupis.size() + 1);
newMupi.setName(name);
newMupi.setYou(rgFinish.getCheckedRadioButtonId() == R.id.rb_painted);
newMupi.setBancais(new ArrayList<>());
Data.mupis.add(newMupi);
refreshCallback.run();
});
builder.setNegativeButton("取消", null);
builder.show();
}
} E FATAL EXCEPTION: main
Process: com.example.kucun2, PID: 22195
java.lang.IllegalArgumentException: com.example.kucun2.entity.data.SynchronizableEntity is not an interface
at java.lang.reflect.Proxy$ProxyClassFactory.apply(Proxy.java:635)
at java.lang.reflect.Proxy$ProxyClassFactory.apply(Proxy.java:602)
at java.lang.reflect.WeakCache$Factory.get(WeakCache.java:230)
at java.lang.reflect.WeakCache.get(WeakCache.java:127)
at java.lang.reflect.Proxy.getProxyClass0(Proxy.java:438)
at java.lang.reflect.Proxy.newProxyInstance(Proxy.java:873)
at com.example.kucun2.entity.data.SynchronizedList.createProxy(SynchronizedList.java:186)
at com.example.kucun2.entity.data.SynchronizedList.add(SynchronizedList.java:263)
at com.example.kucun2.ui.jinhuo.AddInventoryFragment.createAndSaveDingdan(AddInventoryFragment.java:445)
at com.example.kucun2.ui.jinhuo.AddInventoryFragment.lambda$showNewDingdanDialog$8(AddInventoryFragment.java:423)
at com.example.kucun2.ui.jinhuo.AddInventoryFragment.$r8$lambda$viLBw5kNmkDSVG17JoXzuH5G85E(Unknown Source:0)
at com.example.kucun2.ui.jinhuo.AddInventoryFragment$$ExternalSyntheticLambda20.onClick(D8$$SyntheticClass:0)
at com.android.internal.app.AlertController$ButtonHandler.handleMessage(AlertController.java:250)
at android.os.Handler.dispatchMessage(Handler.java:109)
at android.os.Looper.loopOnce(Looper.java:250)
at android.os.Looper.loop(Looper.java:340)
at android.app.ActivityThread.main(ActivityThread.java:9913)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:621)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:957)
2025-06-09 20:52:42.415 22195-22195 Process com.example.kucun2 I Sending signal. PID: 22195 SIG: 9
2025-06-09 21:35:57.386 22849-22849 AndroidRuntime com.example.kucun2 E FATAL EXCEPTION: main
Process: com.example.kucun2, PID: 22849
java.lang.ClassCastException: $Proxy4 cannot be cast to com.example.kucun2.entity.data.SynchronizableEntity
at com.example.kucun2.entity.data.SynchronizedList.createProxy(SynchronizedList.java:188)
at com.example.kucun2.entity.data.SynchronizedList.add(SynchronizedList.java:265)
at com.example.kucun2.ui.jinhuo.AddInventoryFragment.createAndSaveDingdan(AddInventoryFragment.java:445)
at com.example.kucun2.ui.jinhuo.AddInventoryFragment.lambda$showNewDingdanDialog$8(AddInventoryFragment.java:423)
at com.example.kucun2.ui.jinhuo.AddInventoryFragment.$r8$lambda$viLBw5kNmkDSVG17JoXzuH5G85E(Unknown Source:0)
at com.example.kucun2.ui.jinhuo.AddInventoryFragment$$ExternalSyntheticLambda20.onClick(D8$$SyntheticClass:0)
at com.android.internal.app.AlertController$ButtonHandler.handleMessage(AlertController.java:250)
at android.os.Handler.dispatchMessage(Handler.java:109)
at android.os.Looper.loopOnce(Looper.java:250)
at android.os.Looper.loop(Looper.java:340)
at android.app.ActivityThread.main(ActivityThread.java:9913)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:621)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:957)