FarmDialog.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. <template>
  2. <custom-dialog :visible.sync="dialogVisible" title="我的农场" @close="onClose">
  3. <view class="farm-container" @click="onContainerClick">
  4. <view class="farm-beds">
  5. <view class="farm-grid upper-bed">
  6. <view class="row row-1">
  7. <view v-for="index in 3" :key="index-1"
  8. class="farm-plot"
  9. :class="getPlotClass(plots[index-1])"
  10. @click.stop="onPlotClick(index-1)">
  11. <view class="plot-content">
  12. <view v-if="plots[index-1].state !== 'locked'" class="crop-stage">
  13. <image v-if="plots[index-1].state === 'growing' || plots[index-1].state === 'harvestable'"
  14. :src="getCropImage(plots[index-1])"
  15. mode="aspectFit"
  16. class="crop-image">
  17. </image>
  18. </view>
  19. <view class="plot-state-text" :class="{ 'state-changed': plots[index-1].stateChanged }">
  20. {{ getPlotStateText(plots[index-1].state) }}
  21. </view>
  22. </view>
  23. </view>
  24. </view>
  25. <view class="row row-2">
  26. <view v-for="index in 4" :key="index+2"
  27. class="farm-plot"
  28. :class="getPlotClass(plots[index+2])"
  29. @click.stop="onPlotClick(index+2)">
  30. <view class="plot-content">
  31. <view v-if="plots[index+2].state !== 'locked'" class="crop-stage">
  32. <image v-if="plots[index+2].state === 'growing' || plots[index+2].state === 'harvestable'"
  33. :src="getCropImage(plots[index+2])"
  34. mode="aspectFit"
  35. class="crop-image">
  36. </image>
  37. </view>
  38. <view class="plot-state-text" :class="{ 'state-changed': plots[index+2].stateChanged }">
  39. {{ getPlotStateText(plots[index+2].state) }}
  40. </view>
  41. </view>
  42. </view>
  43. </view>
  44. <view class="row row-3">
  45. <view v-for="index in 3" :key="index+6"
  46. class="farm-plot"
  47. :class="getPlotClass(plots[index+6])"
  48. @click.stop="onPlotClick(index+6)">
  49. <view class="plot-content">
  50. <view v-if="plots[index+6].state !== 'locked'" class="crop-stage">
  51. <image v-if="plots[index+6].state === 'growing' || plots[index+6].state === 'harvestable'"
  52. :src="getCropImage(plots[index+6])"
  53. mode="aspectFit"
  54. class="crop-image">
  55. </image>
  56. </view>
  57. <view class="plot-state-text" :class="{ 'state-changed': plots[index+6].stateChanged }">
  58. {{ getPlotStateText(plots[index+6].state) }}
  59. </view>
  60. </view>
  61. </view>
  62. </view>
  63. </view>
  64. <view class="farm-grid lower-bed">
  65. <view class="row row-1">
  66. <view v-for="index in 3" :key="index+9"
  67. class="farm-plot"
  68. :class="getPlotClass(plots[index+9])"
  69. @click.stop="onPlotClick(index+9)">
  70. <view class="plot-content">
  71. <view v-if="plots[index+9].state !== 'locked'" class="crop-stage">
  72. <image v-if="plots[index+9].state === 'growing' || plots[index+9].state === 'harvestable'"
  73. :src="getCropImage(plots[index+9])"
  74. mode="aspectFit"
  75. class="crop-image">
  76. </image>
  77. </view>
  78. <view class="plot-state-text" :class="{ 'state-changed': plots[index+9].stateChanged }">
  79. {{ getPlotStateText(plots[index+9].state) }}
  80. </view>
  81. </view>
  82. </view>
  83. </view>
  84. <view class="row row-2">
  85. <view v-for="index in 4" :key="index+12"
  86. class="farm-plot"
  87. :class="getPlotClass(plots[index+12])"
  88. @click.stop="onPlotClick(index+12)">
  89. <view class="plot-content">
  90. <view v-if="plots[index+12].state !== 'locked'" class="crop-stage">
  91. <image v-if="plots[index+12].state === 'growing' || plots[index+12].state === 'harvestable'"
  92. :src="getCropImage(plots[index+12])"
  93. mode="aspectFit"
  94. class="crop-image">
  95. </image>
  96. </view>
  97. <view class="plot-state-text" :class="{ 'state-changed': plots[index+12].stateChanged }">
  98. {{ getPlotStateText(plots[index+12].state) }}
  99. </view>
  100. </view>
  101. </view>
  102. </view>
  103. <view class="row row-3">
  104. <view v-for="index in 3" :key="index+16"
  105. class="farm-plot"
  106. :class="getPlotClass(plots[index+16])"
  107. @click.stop="onPlotClick(index+16)">
  108. <view class="plot-content">
  109. <view v-if="plots[index+16].state !== 'locked'" class="crop-stage">
  110. <image v-if="plots[index+16].state === 'growing' || plots[index+16].state === 'harvestable'"
  111. :src="getCropImage(plots[index+16])"
  112. mode="aspectFit"
  113. class="crop-image">
  114. </image>
  115. </view>
  116. <view class="plot-state-text" :class="{ 'state-changed': plots[index+16].stateChanged }">
  117. {{ getPlotStateText(plots[index+16].state) }}
  118. </view>
  119. </view>
  120. </view>
  121. </view>
  122. </view>
  123. </view>
  124. <view class="action-panel" >
  125. <view class="farm-state-indicator" :class="{ 'state-changed': farmStateChanged }">
  126. 当前状态: {{ getFarmStateText(farmState) }}
  127. </view>
  128. <view class="action-buttons">
  129. <button @click.stop="onUnlockClick" >解锁</button>
  130. <button @click.stop="onPlantClick" >播种</button>
  131. <button @click.stop="onHarvestClick" >收获</button>
  132. <!-- <button @click.stop="onUnlockClick" :disabled="!canUnlock">解锁</button>
  133. <button @click.stop="onPlantClick" :disabled="!canPlant">播种</button>
  134. <button @click.stop="onHarvestClick" :disabled="!canHarvest">收获</button> -->
  135. </view>
  136. </view>
  137. </view>
  138. </custom-dialog>
  139. </template>
  140. <script>
  141. import CustomDialog from '@/components/CustomDialog/CustomDialog.vue'
  142. // import { showModal, showToast } from '@/utils/uniapi'
  143. const PLOT_STATES = {
  144. LOCKED: 'locked',
  145. EMPTY: 'empty',
  146. GROWING: 'growing',
  147. HARVESTABLE: 'harvestable'
  148. }
  149. const FARM_STATES = {
  150. IDLE: 'idle',
  151. PLANTING: 'planting',
  152. HARVESTING: 'harvesting'
  153. }
  154. export default {
  155. name: 'FarmDialog',
  156. components: {
  157. CustomDialog
  158. },
  159. props: {
  160. visible: {
  161. type: Boolean,
  162. default: false
  163. },
  164. coins: {
  165. type: Number,
  166. default: 0
  167. }
  168. },
  169. data() {
  170. return {
  171. dialogVisible: false,
  172. farmState: FARM_STATES.IDLE,
  173. farmStateChanged: false,
  174. plots: Array(20).fill().map(() => ({
  175. state: PLOT_STATES.LOCKED,
  176. plantedAt: null,
  177. stateChanged: false
  178. }))
  179. }
  180. },
  181. computed: {
  182. canUnlock() {
  183. return this.farmState === FARM_STATES.IDLE && this.hasLockedPlots
  184. },
  185. canPlant() {
  186. return this.farmState === FARM_STATES.IDLE && this.hasEmptyPlots
  187. },
  188. canHarvest() {
  189. return this.farmState === FARM_STATES.IDLE && this.hasHarvestablePlots
  190. },
  191. hasLockedPlots() {
  192. return this.plots.some(plot => plot.state === PLOT_STATES.LOCKED)
  193. },
  194. hasEmptyPlots() {
  195. return this.plots.some(plot => plot.state === PLOT_STATES.EMPTY)
  196. },
  197. hasHarvestablePlots() {
  198. return this.plots.some(plot => plot.state === PLOT_STATES.HARVESTABLE)
  199. },
  200. nextUnlockedPlotIndex() {
  201. return this.plots.findIndex(plot => plot.state === PLOT_STATES.LOCKED)
  202. }
  203. },
  204. watch: {
  205. visible(newVal) {
  206. this.dialogVisible = newVal
  207. if (newVal) {
  208. // 初始化第一块地为空地状态
  209. if (this.plots[0].state === PLOT_STATES.LOCKED) {
  210. this.plots[0].state = PLOT_STATES.EMPTY
  211. }
  212. console.log('农场对话框打开,当前农场状态:', this.farmState)
  213. }
  214. },
  215. farmState: {
  216. handler(newVal, oldVal) {
  217. if (newVal !== oldVal) {
  218. console.log(`农场状态发生变化: ${oldVal} -> ${newVal}`)
  219. this.farmStateChanged = true;
  220. setTimeout(() => {
  221. this.farmStateChanged = false;
  222. }, 300);
  223. }
  224. }
  225. }
  226. },
  227. methods: {
  228. onClose() {
  229. console.log('关闭农场对话框,重置农场状态为空闲')
  230. this.farmState = FARM_STATES.IDLE
  231. this.$emit('update:visible', false)
  232. },
  233. getPlotClass(plot) {
  234. return {
  235. 'is-locked': plot.state === PLOT_STATES.LOCKED,
  236. 'is-empty': plot.state === PLOT_STATES.EMPTY,
  237. 'is-growing': plot.state === PLOT_STATES.GROWING,
  238. 'is-harvestable': plot.state === PLOT_STATES.HARVESTABLE,
  239. 'highlight-empty': this.farmState === FARM_STATES.PLANTING && plot.state === PLOT_STATES.EMPTY,
  240. 'highlight-harvestable': this.farmState === FARM_STATES.HARVESTING && plot.state === PLOT_STATES.HARVESTABLE
  241. }
  242. },
  243. getCropImage(plot) {
  244. if (plot.state === PLOT_STATES.GROWING) {
  245. return '/static/crops/growing.png'
  246. } else if (plot.state === PLOT_STATES.HARVESTABLE) {
  247. return '/static/crops/harvestable.png'
  248. }
  249. return ''
  250. },
  251. updatePlotState(index, newState) {
  252. const plot = this.plots[index];
  253. if (plot.state !== newState) {
  254. console.log(`更新土地 ${index} 状态: ${plot.state} -> ${newState}`)
  255. plot.state = newState;
  256. plot.stateChanged = true;
  257. setTimeout(() => {
  258. plot.stateChanged = false;
  259. }, 300);
  260. }
  261. },
  262. async onUnlockClick() {
  263. if (!this.hasLockedPlots) {
  264. console.log('没有可解锁的土地,保持当前状态:', this.farmState)
  265. uni.showToast({ title: '已经解锁所有土地', icon: 'none' })
  266. return
  267. }
  268. const unlockCost = 100
  269. console.log(`当前金币: ${this.coins}, 解锁费用: ${unlockCost}`)
  270. const result = await uni.showModal({
  271. title: '解锁新土地',
  272. content: `是否使用${unlockCost}金币解锁新土地?\n当前金币:${this.coins}`
  273. })
  274. if (result.confirm) {
  275. if (this.coins < unlockCost) {
  276. console.log(`金币不足,需要 ${unlockCost} 金币,当前只有 ${this.coins} 金币`)
  277. uni.showToast({ title: '金币不够', icon: 'none' })
  278. return
  279. }
  280. console.log(`解锁成功,扣除 ${unlockCost} 金币,剩余 ${this.coins - unlockCost} 金币`)
  281. this.$emit('update:coins', this.coins - unlockCost)
  282. this.updatePlotState(this.nextUnlockedPlotIndex, PLOT_STATES.EMPTY)
  283. } else {
  284. console.log('用户取消解锁,保持当前状态:', this.farmState)
  285. }
  286. },
  287. onPlantClick() {
  288. console.log(`点击播种按钮,当前农场状态: ${this.farmState}`);
  289. if (this.farmState === FARM_STATES.PLANTING) {
  290. console.log('取消播种模式,切换为空闲状态');
  291. this.farmState = FARM_STATES.IDLE;
  292. } else {
  293. console.log('进入播种模式,请选择要播种的空地');
  294. this.farmState = FARM_STATES.PLANTING;
  295. }
  296. },
  297. onHarvestClick() {
  298. console.log(`点击收获按钮,当前农场状态: ${this.farmState}`);
  299. if (this.farmState === FARM_STATES.HARVESTING) {
  300. console.log('取消收获模式,切换为空闲状态');
  301. this.farmState = FARM_STATES.IDLE;
  302. } else {
  303. console.log('进入收获模式,请选择要收获的土地');
  304. this.farmState = FARM_STATES.HARVESTING;
  305. }
  306. },
  307. onPlotClick(index) {
  308. const plot = this.plots[index]
  309. console.log(`点击土地 ${index},当前状态: ${plot.state},农场状态: ${this.farmState}`)
  310. if (plot.state === PLOT_STATES.LOCKED) {
  311. console.log(`土地 ${index} 未解锁,无法操作`)
  312. uni.showToast({ title: '请先解锁该土地', icon: 'none' })
  313. return
  314. }
  315. if (this.farmState === FARM_STATES.PLANTING) {
  316. console.log(`当前为播种状态,尝试在土地 ${index} 播种`)
  317. if (plot.state !== PLOT_STATES.EMPTY) {
  318. console.log(`土地 ${index} 不是空地,无法播种,当前状态: ${plot.state}`)
  319. uni.showToast({ title: '只有空地可以播种', icon: 'none' })
  320. return
  321. }
  322. console.log(`在土地 ${index} 播种成功,状态更新为生长中`)
  323. this.updatePlotState(index, PLOT_STATES.GROWING)
  324. plot.plantedAt = Date.now()
  325. console.log(`土地 ${index} 开始生长,种植时间: ${new Date(plot.plantedAt).toLocaleString()}`)
  326. setTimeout(() => {
  327. if (plot.state === PLOT_STATES.GROWING) {
  328. console.log(`土地 ${index} 生长完成,状态更新为可收获`)
  329. this.updatePlotState(index, PLOT_STATES.HARVESTABLE)
  330. } else {
  331. console.log(`土地 ${index} 状态已改变,当前状态: ${plot.state},不更新为可收获状态`)
  332. }
  333. }, 5000)
  334. } else if (this.farmState === FARM_STATES.HARVESTING) {
  335. console.log(`当前为收获状态,尝试收获土地 ${index}`)
  336. if (plot.state !== PLOT_STATES.HARVESTABLE) {
  337. console.log(`土地 ${index} 没有可收获的作物,当前状态: ${plot.state}`)
  338. uni.showToast({ title: '没有可以收获的花朵', icon: 'none' })
  339. return
  340. }
  341. console.log(`收获土地 ${index} 成功,状态更新为空地`)
  342. this.updatePlotState(index, PLOT_STATES.EMPTY)
  343. plot.plantedAt = null
  344. console.log(`发送收获完成事件`)
  345. this.$emit('harvest-complete')
  346. } else {
  347. console.log(`当前为空闲状态,点击土地 ${index} 无效,请先选择操作模式`)
  348. }
  349. },
  350. onContainerClick() {
  351. if (this.farmState !== FARM_STATES.IDLE) {
  352. console.log(`点击空白区域,从${this.farmState}状态切换为空闲状态`)
  353. this.farmState = FARM_STATES.IDLE
  354. }
  355. },
  356. getPlotStateText(state) {
  357. const stateTexts = {
  358. [PLOT_STATES.LOCKED]: '未解锁',
  359. [PLOT_STATES.EMPTY]: '空地',
  360. [PLOT_STATES.GROWING]: '生长中',
  361. [PLOT_STATES.HARVESTABLE]: '可收获'
  362. }
  363. return stateTexts[state]
  364. },
  365. getFarmStateText(state) {
  366. const stateTexts = {
  367. [FARM_STATES.IDLE]: '空闲',
  368. [FARM_STATES.PLANTING]: '播种状态',
  369. [FARM_STATES.HARVESTING]: '收获状态'
  370. }
  371. return stateTexts[state]
  372. }
  373. }
  374. }
  375. </script>
  376. <style lang="scss">
  377. @import './FarmDialog.scss';
  378. </style>