ProjectCreate.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559
  1. <template>
  2. <div class="create-container" v-loading="loading">
  3. <div class="title h1">创建项目</div>
  4. <div class="create-body">
  5. <el-form :model="project" :rules="rules" ref="project" label-width="12%" class="demo-project">
  6. <el-form-item label="项目名称" prop="name">
  7. <el-input size="small" v-model="project.name" placeholder="请输入项目名称"></el-input>
  8. </el-form-item>
  9. <el-form-item label="联系人" prop="contactName">
  10. <el-input size="small" v-model="project.contactName" placeholder="请输入联系人姓名"></el-input>
  11. </el-form-item>
  12. <el-form-item label="手机号" prop="contactPhone">
  13. <el-input size="small" v-model="project.contactPhone" placeholder="请输入联系人电话"></el-input>
  14. </el-form-item>
  15. <el-form-item label="预算" prop="budget">
  16. <el-input size="small" type="number" v-model="project.budget" placeholder="请输入项目预算">
  17. <template slot="append">¥</template>
  18. </el-input>
  19. </el-form-item>
  20. <el-form-item label="需求描述" prop="desc">
  21. <el-input type="textarea" style="width: 400px" v-model="project.desc"
  22. placeholder="请输入对项目的描述"></el-input>
  23. </el-form-item>
  24. <!--<el-form-item label="价格" prop="price">-->
  25. <!--<el-input type="number" v-model="project.price">-->
  26. <!--<template slot="append">¥</template>-->
  27. <!--</el-input>-->
  28. <!--</el-form-item>-->
  29. <el-form-item label="平台" prop="platform">
  30. <el-checkbox-group v-model="project.platform">
  31. <span v-for="(item,index) in platforms" :key="index">
  32. <el-checkbox :label="item">{{ item }}&nbsp;&nbsp;&nbsp;&nbsp;</el-checkbox>
  33. </span>
  34. </el-checkbox-group>
  35. </el-form-item>
  36. <el-form-item label="服务类型" prop="type">
  37. <el-checkbox-group v-model="project.type">
  38. <span v-for="(item,index) in serviceType" :key="index">
  39. <el-checkbox :label="item" name="type">{{item}}&nbsp;&nbsp;&nbsp;&nbsp;</el-checkbox>
  40. </span>
  41. </el-checkbox-group>
  42. </el-form-item>
  43. <el-form-item label="项目可见性" prop="resource">
  44. <el-tabs
  45. :tab-position="tabPosition"
  46. v-model="project.resource"
  47. style="max-height: 200px;"
  48. >
  49. <el-tab-pane :label="resourceType[0]" name="0">
  50. <el-radio-group v-model="project.institution" prop="institution">
  51. <el-radio :label="item" name="type" v-for="item,index in institutionArray" :key="index">{{item.name}}
  52. </el-radio>
  53. </el-radio-group>
  54. </el-tab-pane>
  55. <el-tab-pane :label="resourceType[1]" name="1">
  56. <provincecity
  57. ref="addFormProvince"
  58. @selectChange="locationChange"
  59. :provinceCode="project.location.provinceCode"
  60. :cityCode="project.location.cityCode"
  61. ></provincecity>
  62. </el-tab-pane>
  63. <el-tab-pane :label="resourceType[2]" name="2"></el-tab-pane>
  64. </el-tabs>
  65. </el-form-item>
  66. <el-form-item label="需求文档" prop="doc">
  67. <el-upload
  68. style="width: 400px"
  69. drag
  70. class="upload-demo"
  71. action=""
  72. :on-remove="handleRemove"
  73. :before-remove="beforeRemove"
  74. :limit="1"
  75. :on-exceed="handleExceed"
  76. :before-upload="beforeFileUpload"
  77. :http-request="uploadRequireDoc"
  78. :file-list="project.doc"
  79. >
  80. <i class="el-icon-upload"></i>
  81. <div class="el-upload__text">
  82. 将文件拖到此处,或
  83. <em>点击上传</em>
  84. </div>
  85. </el-upload>
  86. </el-form-item>
  87. <el-form-item label="安装包" prop="file">
  88. <el-upload
  89. drag
  90. style="width: 400px"
  91. class="upload-demo"
  92. action=""
  93. :on-remove="handleRemove"
  94. :limit="1"
  95. :on-exceed="handleExceed"
  96. :before-upload="beforeApkUpload"
  97. :http-request="uploadApkFile"
  98. :file-list="project.file"
  99. >
  100. <i class="el-icon-upload"></i>
  101. <div class="el-upload__text">
  102. 将文件拖到此处,或
  103. <em>点击上传</em>
  104. </div>
  105. </el-upload>
  106. </el-form-item>
  107. <el-form-item label="项目截止时间" prop="datetime">
  108. <div class="block">
  109. <el-date-picker
  110. size="small"
  111. v-model="project.datetime"
  112. type="datetime"
  113. placeholder="选择截止时间"
  114. align="right"
  115. :picker-options="pickerOptions"
  116. ></el-date-picker>
  117. </div>
  118. </el-form-item>
  119. <el-form-item>
  120. <div class="btn btn-medium btn-info" v-on:click="submitForm('project')">立即申请</div>
  121. <div class="btn btn-medium" @click="resetForm('project')">重置</div>
  122. </el-form-item>
  123. </el-form>
  124. </div>
  125. </div>
  126. </template>
  127. <script>
  128. import Http from '@/js/http.js'
  129. import Apis from '@/js/api.js'
  130. import provincecity from '@/components/commons/ProvinceCity'
  131. import provinceCityJSON from '@/constants/provinceCity.json'
  132. import ResourceType from '@/constants/enum/resource-type'
  133. import {notify} from '@/constants/index'
  134. import {
  135. checkFileType,
  136. getAllInstitutions,
  137. getAllPlatformTypes,
  138. getAllServiceTypes,
  139. getProvinceNameByProvinceCode,
  140. storageGet
  141. } from '@/js/index'
  142. export default {
  143. name: 'ProjectCreate',
  144. components: {
  145. provincecity
  146. },
  147. data () {
  148. var validatePass = (rule, value, callback) => {
  149. var reg = /^(0|86|17951)?(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$/
  150. if (this.contactPhone) {
  151. if (!reg.test(this.contactPhone)) {
  152. callback(new Error('请检查手机号码'))
  153. } else {
  154. callback()
  155. }
  156. }
  157. }
  158. return {
  159. user: {},
  160. loading: false,
  161. tabPosition: 'top',
  162. institutionArray: [],
  163. platforms: [],
  164. serviceType: [],
  165. resourceType: ResourceType,
  166. project: {
  167. userId: 0,
  168. name: '',
  169. contactName: '',
  170. contactPhone: '',
  171. type: [],
  172. platform: [],
  173. desc: '',
  174. doc: [],
  175. file: [],
  176. requireDocUrl: '',
  177. fileUrl: '',
  178. resource: '0',
  179. location: {provinceCode: '3200', cityCode: '3201'},
  180. institution: {},
  181. datetime: '',
  182. price: '',
  183. usage: '',
  184. budget: ''
  185. },
  186. pickerOptions: {
  187. shortcuts: [
  188. {
  189. text: '今天',
  190. onClick (picker) {
  191. picker.$emit('pick', new Date())
  192. }
  193. },
  194. {
  195. text: '昨天',
  196. onClick (picker) {
  197. const date = new Date()
  198. date.setTime(date.getTime() - 3600 * 1000 * 24)
  199. picker.$emit('pick', date)
  200. }
  201. },
  202. {
  203. text: '一周前',
  204. onClick (picker) {
  205. const date = new Date()
  206. date.setTime(date.getTime() - 3600 * 1000 * 24 * 7)
  207. picker.$emit('pick', date)
  208. }
  209. }
  210. ]
  211. },
  212. rules: {
  213. name: [
  214. {required: true, message: '请输入项目名称', trigger: 'blur'},
  215. {min: 5, max: 50, message: '项目名称长度在 5 到 50 个字符', trigger: 'blur'}
  216. ],
  217. contactName: [
  218. {required: true, message: '请输入联系人姓名', trigger: 'blur'}
  219. // { min: 3, max: 5, message: "长度在 3 到 5 个字符", trigger: "blur" }
  220. ],
  221. contactPhone: [
  222. {required: true, message: '请输入手机号', trigger: 'blur'},
  223. //{min: 11, max: 11, message: '请输入正确的手机号', trigger: 'blur'}
  224. ],
  225. type: [
  226. {
  227. type: 'array',
  228. required: true,
  229. message: '请至少选择一种服务类型',
  230. trigger: 'change'
  231. }
  232. ],
  233. platform: [
  234. {
  235. type: 'array',
  236. required: true,
  237. message: '请至少选择一个平台',
  238. trigger: 'change'
  239. }
  240. ],
  241. desc: [{required: false, message: '请填写描述', trigger: 'blur'}],
  242. //price: [{required: true, message: '请填写价格', trigger: 'blur'}],
  243. budget: [
  244. {required: true, message: '预算不可为空', trigger: 'blur'},
  245. {
  246. validator: (rule, value, callback) => {
  247. if(value < 0){
  248. callback(new Error('请输入不小于0的数'))
  249. } else {
  250. callback()
  251. }
  252. }, trigger: 'blur'
  253. },
  254. ],
  255. resource: [
  256. {required: true},
  257. {
  258. validator: (rule, value, callback) => {
  259. if (value == 0 && this.project.institution.id == null) {
  260. callback(new Error('定向发布至少要选择一个区域管理员'))
  261. } else {
  262. callback()
  263. }
  264. }, trigger: 'change'
  265. },
  266. ],
  267. datetime:[{required: true, message: '截止时间不可为空', trigger: 'blur'}],
  268. }
  269. }
  270. },
  271. mounted () {
  272. this.$nextTick(() => {
  273. this.init()
  274. })
  275. },
  276. watch: {
  277. serviceType (val) {
  278. this.serviceType = val
  279. },
  280. institutionArray (val) {
  281. this.institutionArray = val
  282. },
  283. // 'project.institution' () {
  284. // if (this.project.institution) {
  285. // this.$refs.addFormProvince.resetProviceCity()
  286. // this.project.location = {provinceCode: '', cityCode: ''}
  287. // }
  288. // },
  289. // 'project.location' () {
  290. // if (this.project.location.provinceCode || this.project.location.cityCode) {
  291. // this.project.institution = ''
  292. // }
  293. // },
  294. // 'project.resource' () {
  295. // if (this.project.resource == '2') {
  296. // this.$refs.addFormProvince.resetProviceCity()
  297. // this.project.institution = ''
  298. // this.project.location = {provinceCode: '', cityCode: ''}
  299. // }
  300. // },
  301. deep: true
  302. },
  303. methods: {
  304. updateLocation (location) {
  305. var provinceName = ''
  306. var cityName = ''
  307. for (var item of provinceCityJSON.provinces) {
  308. if (item.code === location.provinceCode) {
  309. provinceName = item.name
  310. for (var city of item.cities) {
  311. if (city.code === location.cityCode) {
  312. cityName = city.name
  313. break
  314. }
  315. }
  316. }
  317. }
  318. return provinceName + ' / ' + cityName
  319. },
  320. locationChange (provinceId, cityId) {
  321. if (provinceId || cityId) {
  322. this.project.location = {provinceCode: provinceId, cityCode: cityId}
  323. }
  324. },
  325. init () {
  326. this.setServiceType()
  327. this.setPlatforms()
  328. this.setInstitution()
  329. this.setUserInfo()
  330. // this.project.platform.map(item => {
  331. // this.platformType.push(PlatformType[item])
  332. // })
  333. },
  334. submitForm () {
  335. this.$refs['project'].validate(valid => {
  336. if (valid) {
  337. //console.log(this.project)
  338. this.showLoading()
  339. const newLocation = getProvinceNameByProvinceCode(this.project.location.provinceCode, this.project.location.cityCode)
  340. const newProject = {
  341. userId: this.user.userVO.id,
  342. name: this.project.name,
  343. type: this.project.type,
  344. platform: this.project.platform,
  345. desc: this.project.desc,
  346. resource: this.project.resource,
  347. location: newLocation,
  348. institution: this.project.institution.id,
  349. contactName: this.project.contactName,
  350. contactPhone: this.project.contactPhone,
  351. doc: this.project.requireDocUrl,
  352. file: this.project.fileUrl,
  353. budget: this.project.budget,
  354. datetime: this.project.datetime,
  355. usage: this.project.usage,
  356. price: this.project.price
  357. }
  358. Http.post(Apis.PROJECT.CREATE_PROJECT, newProject).then((res) => {
  359. //notify('success', '创建成功')
  360. this.hideLoading()
  361. this.createProjectSuccess(res.projectDetails.id)
  362. // if (window.history.length <= 1) {
  363. // this.$router.push({path: '/'})
  364. // return false
  365. // } else {
  366. // this.$router.go(-1)
  367. // }
  368. }).catch(error => {
  369. //console.log(error)
  370. notify('error', error.data)
  371. })
  372. } else {
  373. console.log(valid)
  374. notify('error','表单填写错误!')
  375. return false
  376. }
  377. })
  378. },
  379. resetForm (formName) {
  380. this.$refs[formName].resetFields()
  381. this.project.name = ''
  382. this.project.type = []
  383. this.project.platform = []
  384. this.project.desc = ''
  385. this.project.file = ''
  386. this.project.doc = ''
  387. this.project.contactName = ''
  388. this.project.contactPhone = ''
  389. this.project.resource = '非定向'
  390. this.project.institution = ''
  391. this.project.datetime = ''
  392. this.project.price = ''
  393. this.project.usage = ''
  394. this.project.budget = ''
  395. },
  396. beforeApkUpload (file) {
  397. const fileType = ['exe', 'apk', 'dmg']
  398. return checkFileType(file, fileType, this.beforeApkUploadError)
  399. },
  400. beforeApkUploadError () {
  401. this.$message.error('上传文件只能是exe,dmg,apk格式!')
  402. },
  403. beforeFileUpload (file) {
  404. const fileTypeList = ['pdf', 'xls', 'xlsx', 'doc', 'docx', 'txt']
  405. return checkFileType(file, fileTypeList, this.beforeFileUploadError)
  406. },
  407. beforeFileUploadError () {
  408. this.$message.error('上传文件只能是 PDF 、 DOC 、DOCX 、XLS、TXT、XLSX 格式!')
  409. },
  410. loadData () {
  411. Http.get(Apis.PAGE.PROJECT_DETAIL_PAGE).then((res) => {
  412. this.project = res.project
  413. })
  414. },
  415. handleRemove (file, fileList) {
  416. //console.log(file, fileList)
  417. },
  418. handleExceed (files, fileList) {
  419. this.$message.warning(
  420. `当前限制选择 1 个文件,本次选择了 ${
  421. files.length
  422. } 个文件,共选择了 ${files.length + fileList.length} 个文件`
  423. )
  424. },
  425. beforeRemove (file, fileList) {
  426. //return this.$confirm(`确定移除 ${file.name}?`)
  427. },
  428. uploadRequireDoc (param) {
  429. this.showLoading()
  430. const formData = new FormData()
  431. let config = {
  432. //添加请求头
  433. headers: {'Content-Type': 'multipart/form-data'},
  434. }
  435. formData.append('file', param.file)
  436. Http.upload(Apis.FILE.REQUIREMENT_FILE.replace('{userId}', this.user.userVO.id), formData, config).then((res) => {
  437. //console.log('上传成功')
  438. this.hideLoading()
  439. notify('success', '需求文档上传成功')
  440. this.project.requireDocUrl = res.data
  441. //console.log(this.project.doc)
  442. //console.log(res.data)
  443. }).catch((error) => {
  444. this.hideLoading()
  445. notify('error', '需求文档上传失败:' + error.data)
  446. })
  447. },
  448. uploadApkFile (param) {
  449. this.showLoading()
  450. const formData = new FormData()
  451. let config = {
  452. //添加请求头
  453. headers: {'Content-Type': 'multipart/form-data'},
  454. }
  455. formData.append('file', param.file)
  456. Http.upload(Apis.FILE.APK.replace('{userId}', this.user.userVO.id), formData, config).then((res) => {
  457. this.hideLoading()
  458. notify('success', '文件上传成功')
  459. this.project.fileUrl = res.data
  460. console.log(res)
  461. }).catch((error) => {
  462. this.hideLoading()
  463. notify('error', '文件上传失败:' + error.data)
  464. })
  465. },
  466. setServiceType () {
  467. getAllServiceTypes().then((res) => {
  468. this.serviceType = res
  469. }).catch((error) => {
  470. notify('error', '获取项目服务类型列表失败')
  471. })
  472. },
  473. setPlatforms () {
  474. this.platforms = getAllPlatformTypes()
  475. },
  476. setInstitution () {
  477. getAllInstitutions().then((res) => {
  478. this.institutionArray = res
  479. })
  480. },
  481. setUserInfo () {
  482. this.user = storageGet('user')
  483. },
  484. createProjectSuccess (projectId) {
  485. this.$alert('项目创建成功', '创建成功', {
  486. confirmButtonText: '确定',
  487. callback: action => {
  488. this.$router.push({
  489. name: 'Project',
  490. params: {projectId: projectId}
  491. })
  492. }
  493. })
  494. },
  495. showLoading () {
  496. this.loading = true
  497. },
  498. hideLoading () {
  499. this.loading = false
  500. }
  501. }
  502. }
  503. </script>
  504. <style lang="less" scoped>
  505. .el-col {
  506. padding: 0 !important;
  507. }
  508. .el-row {
  509. margin-bottom: 10px;
  510. }
  511. .el-radio {
  512. margin: 10px 20px 10px 0;
  513. }
  514. .el-form-item /deep/ .el-tabs__content {
  515. max-height: 120px !important;
  516. overflow: auto;
  517. }
  518. .el-input {
  519. width: 400px;
  520. }
  521. </style>
  522. <!--<el-form-item label="联系方式" prop="contact">-->
  523. <!--<div>-->
  524. <!--<el-row :gutter="2">-->
  525. <!--<el-col :span="2">-->
  526. <!--<span>联系人</span>-->
  527. <!--</el-col>-->
  528. <!--<el-col :span="10">-->
  529. <!--<el-input v-model="project.contactName" placeholder="请输入联系人姓名"></el-input>-->
  530. <!--</el-col>-->
  531. <!--</el-row>-->
  532. <!--<el-row :gutter="2">-->
  533. <!--<el-col :span="2">-->
  534. <!--<span>联系人电话</span>-->
  535. <!--</el-col>-->
  536. <!--<el-col :span="10">-->
  537. <!--<el-input v-model="project.contactPhone" placeholder="请输入联系人电话"></el-input>-->
  538. <!--</el-col>-->
  539. <!--</el-row>-->
  540. <!--</div>-->
  541. <!--</el-form-item>-->
  542. <!--<el-form-item label="用途" prop="usage">-->
  543. <!--<el-input v-model="project.usage"></el-input>-->
  544. <!--</el-form-item>-->