张延森 2 年前
父节点
当前提交
289363b4a6
共有 6 个文件被更改,包括 263 次插入49 次删除
  1. 115
    0
      src/components/OrgPicker/index.vue
  2. 2
    49
      src/pages/index.vue
  3. 133
    0
      src/pages/invoice/fill.vue
  4. 1
    0
      src/router/index.js
  5. 6
    0
      src/services/org.js
  6. 6
    0
      src/vant.js

+ 115
- 0
src/components/OrgPicker/index.vue 查看文件

@@ -0,0 +1,115 @@
1
+<template>
2
+  <div class="org-picker">
3
+    <div class="picker-search">
4
+      <van-search v-model="searchValue" placeholder="请输入公司名称" @search="onSearch" />
5
+    </div>
6
+    <div class="picker-list">
7
+      <van-list v-model:loading="loading" :finished="finished" finished-text="我们是有底线的" @load="onLoad">
8
+        <van-cell v-for="org in orgList" :key="org.orgId" :title="org.name" @click="onClick(org)">
9
+          <template #right-icon v-if="org.orgId === orgSelected.orgId">
10
+            <van-icon name="success" />
11
+          </template>
12
+        </van-cell>
13
+      </van-list>
14
+    </div>
15
+    <div class="picker-action">
16
+      <van-button type="primary" @click="onSubmit" block>确定</van-button>
17
+    </div>
18
+  </div>
19
+</template>
20
+
21
+<script setup>
22
+import { computed, watch, ref, onMounted } from 'vue'
23
+import { getOrgList } from '@/services/org'
24
+
25
+
26
+const searchValue = ref('')
27
+const orgSelected = ref({})
28
+const orgResult = ref({})
29
+const loading = ref(false)
30
+const finished = ref(false)
31
+const pageSize = 20
32
+
33
+const props = defineProps({
34
+  modelValue: String
35
+})
36
+const emit = defineEmits(['update:modelValue', 'change'])
37
+
38
+const orgList = computed(() => orgResult.value.records || [])
39
+watch(props.modelValue, (val) => {
40
+  orgSelected.value = { orgId: val }
41
+})
42
+
43
+const queryData = (params) => {
44
+  getOrgList({ ...params, isSystem: true })
45
+    .then((res) => {
46
+      const first = res.current === 1
47
+      if (first) {
48
+        orgResult.value = res
49
+      } else {
50
+        orgResult.value = {
51
+          ...res,
52
+          records: orgResult.value.records.concat(res.records)
53
+        }
54
+      }
55
+
56
+      loading.value = false
57
+      finished.value = res.current >= res.pages
58
+    })
59
+    .catch(() => {
60
+      loading.value = false
61
+      finished.value = true
62
+    })
63
+}
64
+
65
+const onSearch = (val) => {
66
+  queryData({ pageNum: 1, pageSize, name: val })
67
+}
68
+
69
+const onCancel = () => {
70
+  queryData({ pageNum: 1, pageSize })
71
+}
72
+
73
+// 组件加载, onLoad 就会执行一次
74
+// 所以 onMounted 里面不需要初始化执行了
75
+const onLoad = () => {
76
+  const pageNum = orgResult.value.current ? orgResult.value.current + 1 : 1
77
+  queryData({ pageNum, pageSize, name: searchValue.value })
78
+}
79
+
80
+const onClick = (org) => {
81
+  orgSelected.value = org
82
+}
83
+
84
+const onSubmit = () => {
85
+  emit('update:modelValue', orgSelected.value.orgId)
86
+  if (orgSelected.value.orgId && orgSelected.value.orgName) {
87
+    emit('change', orgSelected.value)
88
+  } else {
89
+    emit('change')
90
+  }
91
+}
92
+
93
+</script>
94
+
95
+<style lang="less" scoped>
96
+.org-picker {
97
+  display: flex;
98
+  flex-direction: column;
99
+  height: 100vh;
100
+  overflow: hidden;
101
+
102
+  .picker-search {
103
+    flex: none;
104
+  }
105
+  .picker-list {
106
+    flex: 1;
107
+    overflow-y: auto;
108
+  }
109
+  .picker-action {
110
+    flex: none;
111
+    box-sizing: border-box;
112
+    padding: 4px 8px;
113
+  }
114
+}
115
+</style>

+ 2
- 49
src/pages/index.vue 查看文件

@@ -1,54 +1,7 @@
1 1
 <template>
2
-  <div>
3
-    <van-search
4
-      v-model="value"
5
-      show-action
6
-      placeholder="请输入单位名称"
7
-      @search="onSearch"
8
-    >
9
-      <template #action>
10
-        <div @click="onSearch">搜索</div>
11
-      </template>
12
-    </van-search>
13
-    <van-list
14
-      v-model:loading="loading"
15
-      :finished="finished"
16
-      finished-text="没有更多了"
17
-      @load="onLoad"
18
-    >
19
-      <van-cell v-for="item in list" :key="item" :title="item" />
20
-    </van-list>
21
-  </div>
2
+  <OrgPicker />
22 3
 </template>
23 4
 
24 5
 <script setup>
25
-import { ref } from 'vue';
26
-
27
-const value = ref()
28
-const list = ref([]);
29
-const loading = ref(false);
30
-const finished = ref(false);
31
-
32
-const onLoad = () => {
33
-  // 异步更新数据
34
-  // setTimeout 仅做示例,真实场景中一般为 ajax 请求
35
-  setTimeout(() => {
36
-    for (let i = 0; i < 10; i++) {
37
-      list.value.push(list.value.length + 1);
38
-    }
39
-
40
-    // 加载状态结束
41
-    loading.value = false;
42
-
43
-    // 数据全部加载完成
44
-    if (list.value.length >= 40) {
45
-      finished.value = true;
46
-    }
47
-  }, 1000);
48
-};
49
-
50
-const onSearch = (val) => {
51
-  const text = val || value.value
52
-}
53
-
6
+import OrgPicker from '@/components/OrgPicker/index.vue'
54 7
 </script>

+ 133
- 0
src/pages/invoice/fill.vue 查看文件

@@ -0,0 +1,133 @@
1
+<template>
2
+  <van-form @failed="onFailed">
3
+    <van-cell-group title="开票单位">
4
+      <van-field
5
+        label="开票单位"
6
+        v-model="formData.orgName"
7
+        name="orgName"
8
+        placeholder="请输入开票单位"
9
+        :rules="[{ required: true, message: '请输入开票单位' }]"
10
+      />
11
+      <van-field
12
+        label="纳 税 号"
13
+        v-model="formData.taxNo"
14
+        name="taxNo"
15
+        placeholder="请输入纳税识别号"
16
+        :rules="[{ required: true, message: '请输入纳税识别号' }]"
17
+      />
18
+      <van-field
19
+        label="单位地址"
20
+        v-model="formData.address"
21
+        name="address"
22
+        placeholder="请输入单位地址"
23
+        :rules="[{ required: true, message: '请输入单位地址' }]"
24
+      />
25
+      <van-field
26
+        label="单位电话"
27
+        v-model="formData.phone"
28
+        name="phone"
29
+        placeholder="请输入单位电话"
30
+        :rules="[{ required: true, message: '请输入单位电话' }]"
31
+      />
32
+      <van-field
33
+        label="开户银行"
34
+        v-model="formData.bankName"
35
+        name="bankName"
36
+        placeholder="请输入开户银行"
37
+        :rules="[{ required: true, message: '请输入开户银行' }]"
38
+      />
39
+      <van-field
40
+        label="开户账户"
41
+        v-model="formData.cardNo"
42
+        name="cardNo"
43
+        placeholder="请输入开户行账号"
44
+        :rules="[{ required: true, message: '请输入开户行账号' }]"
45
+      />
46
+    </van-cell-group>
47
+
48
+    <van-cell-group title="报销信息">
49
+      <van-cell title="报销项目">
50
+        <template #value>
51
+          <span style="color: #000">培训费</span>
52
+        </template>
53
+      </van-cell>
54
+      <van-cell title="开票金额">
55
+        <template #value>
56
+          <span style="color: #f00">600.00</span>
57
+        </template>
58
+      </van-cell>
59
+      <van-cell title="报销项目">
60
+        <template #value>
61
+          <span style="color: #000">住宿费</span>
62
+        </template>
63
+      </van-cell>
64
+      <van-cell title="开票金额">
65
+        <template #value>
66
+          <span style="color: #f00">1200.00</span>
67
+        </template>
68
+      </van-cell>
69
+      <van-cell title="报销项目">
70
+        <template #value>
71
+          <span style="color: #000">餐费</span>
72
+        </template>
73
+      </van-cell>
74
+      <van-cell title="开票金额">
75
+        <template #value>
76
+          <span style="color: #f00">600.00</span>
77
+        </template>
78
+      </van-cell>
79
+    </van-cell-group>
80
+    <div style="margin: 16px;">
81
+      <van-button round block type="primary" native-type="submit">
82
+        提交
83
+      </van-button>
84
+    </div>
85
+  </van-form>
86
+</template>
87
+
88
+<script setup>
89
+  import { reactive } from 'vue';
90
+
91
+  const formData = reactive({
92
+    detailId: undefined,
93
+    invoiceId: undefined,
94
+    invoicePersonId: undefined,
95
+    personId: undefined,
96
+    personName: undefined,
97
+    invoiceOrgId: undefined,
98
+    orgId: undefined,
99
+    orgName: undefined,
100
+    taxNo: undefined,
101
+    address: undefined,
102
+    phone: undefined,
103
+    bankId: undefined,
104
+    bankName: undefined,
105
+    cardNo: undefined,
106
+    invoiceItemTplId: undefined,
107
+    itemName: undefined,
108
+    charge: undefined,
109
+    mergeRemark: undefined,
110
+    stayRemark: undefined,
111
+  })
112
+
113
+  // 校验函数返回 true 表示校验通过,false 表示不通过
114
+  const validator = (val) => /1\d{10}/.test(val);
115
+
116
+  // 校验函数可以直接返回一段错误提示
117
+  const validatorMessage = (val) => `${val} 不合法,请重新输入`;
118
+
119
+  // 校验函数可以返回 Promise,实现异步校验
120
+  const asyncValidator = (val) =>
121
+    new Promise((resolve) => {
122
+      Toast.loading('验证中...');
123
+
124
+      setTimeout(() => {
125
+        Toast.clear();
126
+        resolve(val === '1234');
127
+      }, 1000);
128
+    });
129
+
130
+  const onFailed = (errorInfo) => {
131
+    console.log('failed', errorInfo);
132
+  };
133
+</script>

+ 1
- 0
src/router/index.js 查看文件

@@ -5,6 +5,7 @@ import store from '@/store';
5 5
 
6 6
 const routes = [
7 7
   { path: '/', name: 'index', component: () => import('@/pages/index.vue') },
8
+  { path: '/invoice/fill', name: 'invoice.fill', component: () => import('@/pages/invoice/fill.vue') },
8 9
   { path: '/login', name: 'login', component: () => import('@/pages/login.vue') },
9 10
 ];
10 11
 

+ 6
- 0
src/services/org.js 查看文件

@@ -0,0 +1,6 @@
1
+import request from "@/utils/request";
2
+
3
+// 获取组织列表
4
+export function getOrgList(params) {
5
+  return request.get('/org', { params } )
6
+}

+ 6
- 0
src/vant.js 查看文件

@@ -4,8 +4,11 @@ import {
4 4
   Cell,
5 5
   CellGroup,
6 6
   Dialog,
7
+  Form,
8
+  Field,
7 9
   Loading,
8 10
   List,
11
+  Icon,
9 12
   Notify,
10 13
   ImagePreview,
11 14
   Search,
@@ -22,7 +25,10 @@ export default function vant(app) {
22 25
   app.use(Cell);
23 26
   app.use(CellGroup);
24 27
   app.use(Dialog);
28
+  app.use(Form);
29
+  app.use(Field);
25 30
   app.use(Loading);
31
+  app.use(Icon);
26 32
   app.use(List);
27 33
   app.use(Notify);
28 34
   app.use(ImagePreview);