freshorder.vue 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. <template>
  2. <q-card class="q-pa-md shadow-5">
  3. <!-- 条件组操作栏 -->
  4. <div class="q-mb-md">
  5. <div class="row">
  6. <q-btn
  7. label="添加条件"
  8. icon="add"
  9. color="primary"
  10. @click="addCondition"
  11. />
  12. <q-select
  13. v-model="logicOperator"
  14. :options="['AND', 'OR']"
  15. dense
  16. class="q-ml-md"
  17. style="width: 100px"
  18. />
  19. </div>
  20. </div>
  21. <!-- 拖拽式条件容器 -->
  22. <draggable :list="conditions" handle=".handle">
  23. <div
  24. v-for="(condition, index) in conditions"
  25. :key="condition.id"
  26. class="row q-gutter-sm q-mb-md"
  27. >
  28. <!-- 拖拽手柄 -->
  29. <q-icon name="drag_indicator" class="handle text-grey-6" size="24px" />
  30. <!-- 字段选择 -->
  31. <q-select
  32. v-model="condition.field"
  33. :options="fieldOptions"
  34. label="字段"
  35. dense
  36. emit-value
  37. map-options
  38. style="min-width: 160px"
  39. />
  40. <!-- 运算符 -->
  41. <q-select
  42. v-model="condition.operator"
  43. :options="operatorOptions(condition.field)"
  44. label="条件"
  45. dense
  46. emit-value
  47. map-options
  48. style="min-width: 130px"
  49. />
  50. <!-- 值输入 -->
  51. <component
  52. v-if="condition.field !== 'date'"
  53. :is="inputComponent(condition.field)"
  54. class="col"
  55. />
  56. <template v-else>
  57. <div class="row q-gutter-xs">
  58. <!-- 年 -->
  59. <q-select
  60. v-model="year"
  61. :options="yearOptions"
  62. label="年"
  63. dense
  64. emit-value
  65. @update:model-value="handleChange"
  66. />
  67. <!-- 月 -->
  68. <q-select
  69. v-model="month"
  70. :options="monthOptions"
  71. label="月"
  72. dense
  73. emit-value
  74. :disable="!year"
  75. @update:model-value="handleChange"
  76. />
  77. <!-- 日 -->
  78. <q-select
  79. v-model="day"
  80. :options="dayOptions"
  81. label="日"
  82. dense
  83. emit-value
  84. :disable="!month"
  85. @update:model-value="handleChange"
  86. />
  87. </div>
  88. </template>
  89. <!-- 删除按钮 -->
  90. <q-btn
  91. flat
  92. round
  93. icon="delete"
  94. color="negative"
  95. @click="removeCondition(index)"
  96. />
  97. </div>
  98. </draggable>
  99. <div class="q-mt-md" align="right">
  100. <q-btn label="重置" @click="resetConditions" />
  101. <q-btn label="执行查询" color="primary" @click="executeQuery" />
  102. </div>
  103. <!-- 查询预览 & 操作 -->
  104. <div class="q-mt-lg">
  105. <q-card flat bordered>
  106. <q-card-section>
  107. <div class="text-caption">生成查询条件:</div>
  108. <pre>{{ generatedQuery }}</pre>
  109. </q-card-section>
  110. <q-card-actions align="right"> </q-card-actions>
  111. </q-card>
  112. </div>
  113. </q-card>
  114. </template>
  115. <script>
  116. import draggable from "vuedraggable";
  117. import CustomDateInput from "components/CustomDateInput.vue";
  118. export default {
  119. components: {
  120. draggable,
  121. CustomDateInput,
  122. },
  123. data() {
  124. return {
  125. conditions: [],
  126. logicOperator: "AND",
  127. fieldOptions: [
  128. { label: "物料编码", value: "material_code" },
  129. { label: "物料名称", value: "material_name" },
  130. { label: "批次号", value: "batch" },
  131. { label: "库存数量", value: "quantity" },
  132. { label: "入库日期", value: "date" },
  133. ],
  134. operatorMap: {
  135. default: [
  136. { label: "等于", value: "eq" },
  137. { label: "包含", value: "contains" },
  138. { label: "开头为", value: "startswith" },
  139. ],
  140. quantity: [
  141. { label: "大于", value: "gt" },
  142. { label: "等于", value: "eq" },
  143. { label: "小于", value: "lt" },
  144. ],
  145. date: [
  146. { label: "之前", value: "lte" },
  147. { label: "之后", value: "gte" },
  148. ],
  149. },
  150. };
  151. },
  152. computed: {
  153. // 生成查询参数
  154. generatedQuery() {
  155. return this.conditions
  156. .map((cond) => {
  157. const suffix = {
  158. eq: "",
  159. contains: "__icontains",
  160. startswith: "__istartswith",
  161. gt: "__gt",
  162. lt: "__lt",
  163. gte: "__gte",
  164. lte: "__lte",
  165. }[cond.operator];
  166. return `${cond.field}${suffix}=${cond.value}`;
  167. })
  168. .join(` ${this.logicOperator} `);
  169. },
  170. // 动态输入组件
  171. inputComponent() {
  172. return function (field) {
  173. const components = {
  174. material_code: "q-input",
  175. material_name: "q-input",
  176. batch: "q-input",
  177. quantity: "q-input",
  178. date: "CustomDateInput",
  179. };
  180. return components[field] || "q-input";
  181. };
  182. },
  183. },
  184. methods: {
  185. // 获取运算符选项
  186. operatorOptions(field) {
  187. return this.operatorMap[field] || this.operatorMap.default;
  188. },
  189. // 添加条件
  190. addCondition() {
  191. this.conditions.push({
  192. id: Date.now(),
  193. field: "material_code",
  194. operator: "eq",
  195. value: "",
  196. ...(this.field === "date" && { value: "2025-01-01" }),
  197. });
  198. },
  199. getDefaultDate() {
  200. const today = new Date();
  201. return `${today.getFullYear()}-${(today.getMonth() + 1)
  202. .toString()
  203. .padStart(2, "0")}-01`;
  204. },
  205. // 删除条件
  206. removeCondition(index) {
  207. this.conditions.splice(index, 1);
  208. },
  209. // 重置条件
  210. resetConditions() {
  211. this.conditions = [];
  212. },
  213. // 执行查询
  214. executeQuery() {
  215. console.log("执行查询:", this.generatedQuery);
  216. // 这里接入实际API调用
  217. },
  218. },
  219. };
  220. </script>
  221. <style scoped>
  222. .handle {
  223. cursor: move;
  224. padding: 8px;
  225. }
  226. </style>